Question

Minimum complete definition of Collection interface consists only of two methods: iterator() and size(), which are abstract in AbstractCollection.

Why all other methods not made default in Java 8? Compatibility shouldn't be an issue, for example, Iterator.remove() was abstract until Java 7, but made default since Java 8.

Subclassing from AbstractCollection is inconvenient sometimes, when I want a Collection implementation to be a member of another class hierarchy. Wasn't that one of the reasons why default methods in interfaces actually needed in Java?

The same question about Map, List and other basic interfaces, comprising Java Collection Framework.

UPDATE

Paul Sandoz:

Generally we have only converted existing abstract methods on an interface to non-abstract if there was a compelling reason to aid implementations, such as Iterator.remove.

These are not new methods on Collection, and there are already implementations in AbstractCollection. The advantage of converting these abstract into non-abstract methods its not particularly compelling given one is most likely to inherit from AbstractCollection or provide more efficient implementations.

It would be possible to move all non-abstract methods on AbstractCollection to Collection. If we were starting from a blank sheet of paper that is what we might have done. (Note one cannot do this with all non-abstract methods on AbstractList.)

http://mail.openjdk.java.net/pipermail/core-libs-dev/2014-February/025118.html

Was it helpful?

Solution

The primary goal of default methods is to enable compatible evolution of interfaces. See section 10 of the State of the Lambda document. One of the main directions of this evolution is to facilitate internal iteration. See the Internal vs External Iteration section of State of the Lambda: Libraries Edition. To this end, there are new methods such as Iterable.forEach, Collection.removeIf, and List.replaceAll.

Other methods like List.sort have been added because it allows individual concrete list implementations to provide more efficient sorting algorithms, which cannot be done with Collections.sort.

Finally, default methods have been added for sheer convenience, such as Iterator.remove. Over the years, we and many others have gotten quite annoyed at adding a method remove that simply throws UnsupportedOperationException every time we implemented a new Iterator. The default method remove does this for us. Note, crucially, that this method doesn't actually remove any elements. (How would it?)

It might seem convenient to provide default implementations for a bunch of Collection methods, written in terms of other methods such as iterator. However, I don't think it's very useful, and in fact I'm not sure it's even possible for some methods.

Consider the Collection.contains(Object) method. It's conceivable that one could write a default implementation of this in terms of iterator by stepping through each element and comparing for equality. This would be a very bad implementation for something like a TreeSet or a HashSet. Even the concrete List implementations such as LinkedList and ArrayList provide fast-path implementations that are much more efficient than stepping through an iterator. Having a default implementation of Collection.contains might be a little bit convenient, but really, it doesn't add much value. In practice every collection will want to override it.

Now consider equals. The specification of Collection.equals raises a bunch of subtle issues. Briefly, a Set can only be equal to another Set, and a List can only be equal to another List, and the equals operation must be symmetric. It follows that a Collection that's neither a List nor a Set can never be equal to a List or a Set.

OK, so our Collection.equals default method will have to do a bunch of instanceof checks up front. If both are Lists we can delegate to AbstractList.equals, and if both are Sets we can delegate to AbstractSet.equals. Now let's suppose that this object and the other object neither Lists nor Sets. What if they are different concrete implementations that cannot be equal to each other? We can't tell.

Setting that aside, let's assume that we equality is defined as having the same membership. The only thing we can do is to iterate through each collection. But we can't (in general) make any assumptions about iteration order, so we can't iterate through them simultaneously and compare elements pairwise like we would for lists. Instead, we'd have to load all the elements from one collection into a temporary collection of some kind. It can't be a Set since we might have duplicates. We'd then check each element of the other Collection to make sure that every element in it is in the first one, and that there are no extras in the first one. This isn't terribly difficult, but it's expensive, and some semantics such as order sensitivity are not supported.

I can't imagine any concrete collection subclass actually wanting to use this algorithm.


In summary, using default methods to make collection implementations easier is not one of the design goals of default methods. In addition, while it might seem that providing default methods on Collection would be convenient, they don't actually seem useful. Any reasonable Collection implementation will need to override all the methods in order to provide the semantics it wants without being horribly inefficient.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top