72

As an special case of List.of(...) or Collections.unmodifiableList() - what is the preferred Java 9 way of pointing to an empty and immutable list?

Keep writing

Collections.emptyList();

or switch to

List.of();
Community
  • 1
  • 1
Sormuras
  • 8,491
  • 1
  • 38
  • 64
  • 10
    Close voter(s): I almost voted for primarily opinion, but there are two objective reasons to prefer `emptyList()` and none that I can think of to prefer `List.of()`, which seems to make this on-topic. – chrylis -cautiouslyoptimistic- Sep 08 '16 at 21:36

4 Answers4

45

Collections.emptyList() does not need to create a new object for each call; it's typical, as in OpenJDK, to just return the singleton EMPTY_LIST object. Additionally, it's clearer that you intend to mean an empty list rather than having forgotten to fill in a placeholder.

Use emptyList(); it's both faster (up to Java target level 1.9) and more readable.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
  • 1
    Java 9 source link for [Collections.emptyList()](http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/02d65bf86352/src/java.base/share/classes/java/util/Collections.java#l4409) and [List.of()](http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/02d65bf86352/src/java.base/share/classes/java/util/List.java#l777). – Andreas Sep 08 '16 at 21:52
  • 1
    @Andreas Ah, I didn't realize it was special-cased. Updating. – chrylis -cautiouslyoptimistic- Sep 08 '16 at 21:53
  • 2
    @Andreas Actually, never mind; it's still creating a new empty placeholder. – chrylis -cautiouslyoptimistic- Sep 08 '16 at 21:54
  • 2
    It is, but you could wonder *why* `List.of()` doesn't just call `Collections.emptyList()`. I haven't looked to see if there are any discussions out there, but I guess it's to ensure you always get a *new* list, for the cases where separate instances matter. So, you new instance matters, use `List.of()`. If you don't care, use `Collections.emptyList()`, which also better describes purpose, as you've already said. – Andreas Sep 08 '16 at 21:58
  • 2
    @Andreas As they're both immutable, I can't think of any situation where it could possibly matter; the API requires that empty lists be `equals`, and there's only a single distinct instance from a theoretical perspective. – chrylis -cautiouslyoptimistic- Sep 08 '16 at 22:00
  • 1
    My previous argument doesn't apply to `List.of(E e1)` vs `Collections.singletonList(T o)`. Why have two equal implementations? --- And I meant, for those *very rare* occasions where `list == list` matters (instance equality, not object equality). – Andreas Sep 08 '16 at 22:01
  • @Andreas Might an underlying hotspot optimization reduce the newly created `List.of()` instances to a single one? Maintaining the `List.of() != List.of()` relation. Then, you get the behaviour of `Collections.emptyList()` without the extra static field declared in the class body. – Sormuras Sep 09 '16 at 06:26
  • 1
    @Sormuras JIT can't make references that are supposed to be distinct the same. – chrylis -cautiouslyoptimistic- Sep 09 '16 at 07:05
  • 13
    @Andreas There's no inherent reason `List.of()` couldn't return the same instance every time. It just hasn't been implemented yet. See [JDK-8156079](https://bugs.openjdk.java.net/browse/JDK-8156079). That said, the tradeoff isn't always obvious. Using a cached instance probably saves memory overall, but it also prevents the JIT from making certain optimizations. That certainly happens with the autoboxing cache. The reason that `List.of()` doesn't call `Collections.emptyList()` is that the latter has a well-defined serial form that cannot be changed for compatibility reasons. The new... – Stuart Marks Sep 28 '16 at 23:15
  • 13
    @Sormuras ... collections factories all share a common serial format (a serialization proxy) which will make it easier to change the internal structure if we want to do so in the future. Also, `emptyList()` has slightly more lax behavior when mutator methods are called. For example, `emptyList().addAll(emptyList())` is a no-op, but `List.of().addAll(emptyList())` throws `UnsupportedOperationException`. – Stuart Marks Sep 28 '16 at 23:22
  • 18
    I've fixed [JDK-8156079](https://bugs.openjdk.java.net/browse/JDK-8156079) so that in JDK 9 early access build 144 and later, `List.of()`, `Set.of()`, and `Map.of()` use singletons for empty instances. – Stuart Marks Nov 30 '16 at 14:54
  • 1
    With the fix applied, the performance reason from the accepted answer vanished. The "more readable" fact persists, methinks. – Sormuras Aug 29 '17 at 18:04
  • 14
    `emptyList()` is not faster and `List.of()` "does not need to create a new object for each call" either. The answer is outdated. – user1803551 Oct 07 '17 at 11:44
33

What is the preferred Java 9 way of pointing to an empty and immutable list?

The difference is rather subtle so "preferred" depends on what you want to achieve. Some behavioral differences:

  • List.of will throw an exception on contains(null) invocations.
  • You can deserialize emptyList() on JDK 8 and previous, but not List.of.

In terms or conveying that you want an empty list, emptyList() might look better, but this is just a temporary convention. If developers start using List.of() (which is much shorter than Collections.emptyList()) then it will become a known and accepted way, it's just new. If you think about it, there are some constructs we use which do not always convey what they do by themselves, but we got accustomed to them.

So there is no strictly preferred way. If the behavior does not matter use whatever you want.

user1803551
  • 12,965
  • 5
  • 47
  • 74
  • 1
    This question and its accepted answer (commented by the author) are 1+ year old. – Sormuras Oct 07 '17 at 11:47
  • 6
    @Sormuras I'm well aware, so? People want to see updated information when they read a question. Questions don't age out on this site, they are updated with new answers whenever there is a new way to solve the problem in the question. – user1803551 Oct 07 '17 at 11:50
  • Fair enough. Your other comment below the accepted answer was hidden behind a "show more" link. – Sormuras Oct 07 '17 at 11:54
  • 3
    @Sormuras: [as explicitly stated](https://stackoverflow.com/help/accepted-answer): “*Accepting an answer is not meant to be a definitive and final statement indicating that the question has now been answered perfectly*”… you may accept a newer answer if it fits better or the older is outdated, by the way. – Holger Oct 12 '17 at 06:46
  • 1
    The `contains(null)` bit is quite relevant... Constructors for Immutable objects that also like `null` safety will often do a `contains(null)` check on passed-in collections, in order to guarantee their users that they won't encounter `null` when looking through a provided collection. When a collection was created with `List.of` this throws a NPE, really annoying. The `null` check in the constructor now has to be something in the lines of `collection.stream().filter(Objects::isNull).findAny().isPresent()` – john16384 Apr 21 '19 at 12:16
8

As of JDK 11, If you look at the source code, you see that List.of(), uses a one-time initialized empty list, similar to Collections.emptyList(). So, I'll prefer to use List.of() because:

  • It is a more recent API. So, I think if Java maintainers were satisfied with the previous ways, they wouldn't add a new API.
  • It is more concise.
  • If you use List.of(E... elements) (And you should) for non-empty lists, you can use List.of() for empty ones and enjoy a unified look and feel and get rid of most of the factory methods in Collections API.
AriyaDey
  • 137
  • 1
  • 7
3
  1. emptyList() creates a new empty list instance only once
  2. there is no difference on Readability: maybe List.of() is shorten than Collections.emptyList() but you can use a static import like import static java.util.Collections.emptyList; and then write only emptyList()
Andrea Ciccotta
  • 598
  • 6
  • 16
  • I actually did that for a long time, and some might argue that you can do the same with `import static java.util.List.of;` although that is way less readable... thank you! – maxxyme Apr 08 '22 at 12:55