<div dir="ltr">Thank you for your reply, which explains why there are so few interfaces in the collection framework.<br><div>But I think it still doesn't answer my question: Why doesn't it provide a means to judge the features supported by the collection?<br></div><div><br></div><div>Now that we have the interface default method, can we add a new method to the Collection to obtain the support status of the feature, like this:<br></div><div><br></div><div><div style="background-color:rgb(30,31,34);color:rgb(169,183,198);font-family:"JetBrains Mono",monospace;font-size:13.5pt"><pre><span style="color:rgb(204,120,50)">public record </span>CollectionFeature(String name) {<br>    <span style="color:rgb(204,120,50)">public enum </span>Status {<br>        <span style="color:rgb(152,118,170);font-style:italic">SUPPORTED</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">UNSUPPORTED</span><span style="color:rgb(204,120,50)">, </span><span style="color:rgb(152,118,170);font-style:italic">UNKNOWN<br></span><span style="color:rgb(152,118,170);font-style:italic">    </span>}<br>}</pre><pre><div style="font-family:"JetBrains Mono",monospace;font-size:13.5pt"><pre><span style="color:rgb(204,120,50)">public interface </span>Collection<<span style="color:rgb(80,120,116)">E</span>> <span style="color:rgb(204,120,50)">extends </span>Iterable<<span style="color:rgb(80,120,116)">E</span>> {<br>    CollectionFeature <span style="color:rgb(152,118,170);font-style:italic">ADD_ELEMENT </span>= <span style="color:rgb(204,120,50)">new </span>CollectionFeature(<span style="color:rgb(106,135,89)">"ADD_ELEMENT"</span>)<span style="color:rgb(204,120,50)">;<br></span><span style="color:rgb(204,120,50)"><br></span><span style="color:rgb(204,120,50)">    </span><span style="color:rgb(128,128,128)">// ...<br></span><span style="color:rgb(128,128,128)"><br></span><span style="color:rgb(128,128,128)">    </span><span style="color:rgb(204,120,50)">default </span>CollectionFeature.Status <span style="color:rgb(255,198,109)">supports</span>(CollectionFeature feature) {<br>        <span style="color:rgb(204,120,50)">return </span><span style="color:rgb(152,118,170);font-style:italic">UNKNOWN</span><span style="color:rgb(204,120,50)">;<br></span><span style="color:rgb(204,120,50)">    </span>}<br>}</pre><pre><div style="font-family:"JetBrains Mono",monospace;font-size:13.5pt"><pre><span style="color:rgb(204,120,50)">public interface </span>List<<span style="color:rgb(80,120,116)">E</span>> <span style="color:rgb(204,120,50)">extends </span>Collection<<span style="color:rgb(80,120,116)">E</span>> {<br>    CollectionFeature <span style="color:rgb(152,118,170);font-style:italic">RANDOM_ACCESS </span>= <span style="color:rgb(204,120,50)">new </span>CollectionFeature(<span style="color:rgb(106,135,89)">"RANDOM_ACCESS"</span>)<span style="color:rgb(204,120,50)">;<br></span><span style="color:rgb(204,120,50)">    </span>CollectionFeature <span style="color:rgb(152,118,170);font-style:italic">UPDATE_ELEMENT </span>= <span style="color:rgb(204,120,50)">new </span>CollectionFeature(<span style="color:rgb(106,135,89)">"UPDATE_ELEMENT"</span>)<span style="color:rgb(204,120,50)">;<br></span><span style="color:rgb(204,120,50)"><br></span><span style="color:rgb(204,120,50)">    </span><span style="color:rgb(128,128,128)">// ...<br></span><span style="color:rgb(128,128,128)"><br></span><span style="color:rgb(128,128,128)">    </span><span style="color:rgb(187,181,41)">@Override<br></span><span style="color:rgb(187,181,41)">    </span><span style="color:rgb(204,120,50)">default </span>CollectionFeature.Status <span style="color:rgb(255,198,109)">supports</span>(CollectionFeature feature) {<br>        <span style="color:rgb(204,120,50)">if </span>(feature == <span style="color:rgb(152,118,170);font-style:italic">RANDOM_ACCESS</span>)<br>            <span style="color:rgb(204,120,50)">return this instanceof </span>RandomAccess ? <span style="color:rgb(152,118,170);font-style:italic">SUPPORTED </span>: <span style="color:rgb(152,118,170);font-style:italic">UNSUPPORTED</span><span style="color:rgb(204,120,50)">;<br></span><span style="color:rgb(204,120,50)">        else<br></span><span style="color:rgb(204,120,50)">            return </span><span style="color:rgb(152,118,170);font-style:italic">UNKNOWN</span><span style="color:rgb(204,120,50)">;<br></span><span style="color:rgb(204,120,50)">    </span>}<br>}<br></pre></div></pre></div></pre></div></div><div><br></div><div>Is there anything preventing us from doing this? Or "users should not know what features a collection object supports" is also part of the design?<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jan 30, 2023 at 3:58 PM David Holmes <<a href="mailto:david.holmes@oracle.com">david.holmes@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
<br>
On 30/01/2023 3:37 am, Glavo wrote:<br>
> I quite agree with you. I think the collection framework is in a very <br>
> puzzling state.<br>
> <br>
> The hostility of the new collection factory method introduced by Java 9 <br>
> to null has brought us trouble.<br>
> I can understand that this is to expect users to explicitly declare that <br>
> the elements of the list cannot be null, rather than in an ambiguous state.<br>
> However, this makes migration more difficult, and the cost of scanning <br>
> all elements to ensure that they are not null is also unpleasant.<br>
> I hope to provide an additional set of factory methods for the <br>
> collection to accept nullable elements.<br>
> <br>
> In addition, it is also confusing to share the same interface between <br>
> mutable collections and immutable collections .<br>
> Before encountering UnsupportedOperationException, we can't even know <br>
> what operations a collection supports.<br>
> This problem has existed for a long time, but no solution has been given.<br>
<br>
There is no "solution" because it is not a "problem" it is a design <br>
decision:<br>
<br>
<a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/designfaq.html" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/8/docs/technotes/guides/collections/designfaq.html</a><br>
<br>
You might not like it, or agree with it, but it is what it is.<br>
<br>
Cheers,<br>
David<br>
<br>
> <br>
> On Sun, Jan 29, 2023 at 11:28 PM John Hendrikx <<a href="mailto:john.hendrikx@gmail.com" target="_blank">john.hendrikx@gmail.com</a> <br>
> <mailto:<a href="mailto:john.hendrikx@gmail.com" target="_blank">john.hendrikx@gmail.com</a>>> wrote:<br>
> <br>
>     TLDR; why does contains(null) not just return false for collections<br>
>     that<br>
>     don't allow nulls. Just because the interface allows it, does not mean<br>
>     it should do it as it devalues the usefulness of the abstraction<br>
>     provided by the interface.<br>
> <br>
>     Background:<br>
> <br>
>     I'm someone that likes to check correctness of any constructor or<br>
>     method<br>
>     parameter before allowing an object to be constructed or to be<br>
>     modified,<br>
>     in order to maintain invariants that are provided by the class to<br>
>     its users.<br>
> <br>
>     This ranges from simple null checks, to range checks on numeric values,<br>
>     to complete checks like "is a collection sorted" or is a list of nodes<br>
>     acyclic. Anything I can check in the constructor that may avoid<br>
>     problems<br>
>     further down the line or that may affect what I can guarantee on its<br>
>     own<br>
>     API methods.  For example, if I check in the constructor that something<br>
>     is not null, then the associated getter will guarantee that the<br>
>     returned<br>
>     value is not null.  If I check that a List doesn't contain nulls, then<br>
>     the associated getter will reflect that as well (assuming it is<br>
>     immutable or defensivily copied).<br>
> <br>
>     For collections, this is currently becoming harder and harder because<br>
>     more and more new collections are written to be null hostile.  It is<br>
>     fine if a collection doesn't accept nulls, but throwing NPE when I ask<br>
>     such a collection if it contains null seems to be counter productive,<br>
>     and reduces the usefulness of the collection interfaces.<br>
> <br>
>     This strict interpretation makes the collection interfaces harder to<br>
>     use<br>
>     than necessary. Interfaces are only useful when their contract is well<br>
>     defined. The more things an interface allows or leaves unspecified, the<br>
>     less useful it is for its users.<br>
> <br>
>     I know that the collection interfaces allow this, but you have to ask<br>
>     yourself this important question: how useful is an interface that makes<br>
>     almost no guarantees about what its methods will do? Interfaces like<br>
>     `List`, `Map` and `Set` are passed as method parameters a lot, and to<br>
>     make these useful, implementations of these interfaces should do their<br>
>     best to provide as consistent an experience as is reasonably possible.<br>
>     The alternative is that these interfaces will slowly decline in<br>
>     usefulness as methods will start asking for `ArrayList` instead of<br>
>     `List` to avoid having to deal with a too lenient specification.<br>
> <br>
>     With the collection interfaces I get the impression that recently there<br>
>     has been too much focus on what would be easy for the collection<br>
>     implementation instead of what would be easy for the users of said<br>
>     interfaces. In my opinion, the concerns of the user of interfaces<br>
>     almost<br>
>     always far outweigh the concerns of the implementors of said interfaces.<br>
> <br>
>     In the past, immutable collections were rare, but they get are getting<br>
>     more and more common all the time.  For example, in unit testing.<br>
>     Unfortunately, these immutable collections differ quite a bit from<br>
>     their<br>
>     mutable counterparts.  Some parts are only midly annoying (not<br>
>     accepting<br>
>     `null` as the **value** in a `Map` for example), but other parts<br>
>     require<br>
>     code to be rewritten for it to be able to work as a drop-in replacement<br>
>     for the mutable variant. A simple example is this:<br>
> <br>
>           public void addShoppingItems(Collection<String> shoppingItems) {<br>
>               if (shoppingItems.contains(null)) {  // this looks quite<br>
>     reasonable and safe...<br>
>                   throw new IllegalArgumentException("shoppingItems should<br>
>     not contain nulls");<br>
>               }<br>
> <br>
>               this.shoppingItems.addAll(shoppingItems);<br>
>           }<br>
> <br>
>     Testing this code is annoying:<br>
> <br>
>            x.addShoppingItems(List.of("a", null"));   // can't construct<br>
>     immutable collection with null<br>
> <br>
>            x.addShoppingItems(Arrays.asList("a", null"));  // fine, go back<br>
>     to what we did before then...<br>
> <br>
>     The above problems, I suppose we can live with it; immutable<br>
>     collections<br>
>     don't want `null` although I don't see any reason to not allow it as I<br>
>     can write a similar `List.of` that returns immutable collections<br>
>     that do<br>
>     allow `null`. For JDK code this is a bit disconcerting, as it is<br>
>     supposed to be as flexible as is reasonable without having too much of<br>
>     an opinion about what is good or bad.<br>
> <br>
>     This next one however:<br>
> <br>
>            assertNoExceptionThrown(() -> x.addShoppingItems(List.of("a",<br>
>     "b")));  // not allowed, contains(null) in application code throws NPE<br>
> <br>
>     This is much more insidious; the `contains(null)` check has been a very<br>
>     practical way to check if collections contain null, and this works for<br>
>     almost all collections in common use, so there is no problem.  But now,<br>
>     more and more collections are starting to just throw NPE immediately<br>
>     even just to **check** if a null element is present. This only<br>
>     serves to<br>
>     distinguish themselves loudly from other similar collections that will<br>
>     simply return `false`.<br>
> <br>
>     I think this behavior is detrimental to the java collection interfaces<br>
>     in general, especially since there is a clear answer to the question if<br>
>     such a collection contains null or not. In fact, why `contains` was<br>
>     ever<br>
>     allowed to throw an exception aside from<br>
>     "UnsupportedOperationException"<br>
>     is a mystery to me, and throwing one when one could just as easily<br>
>     return the correct and expected answer seems very opiniated and almost<br>
>     malicious -- not behavior I'd expect from JDK core libraries.<br>
> <br>
>     Also note that there is no way to know in advance if<br>
>     `contains(null)` is<br>
>     going to be throwing the NPE. If interfaces had a method<br>
>     `allowsNulls()`<br>
>     that would already be an improvement.<br>
> <br>
>     --John<br>
> <br>
> <br>
</blockquote></div>