Why is there no "List.reverse()" method in Java?
Why is there no
List.reverse()
method in Java?
Because there is a Collections.reverse(List)
method instead.
Because the API designers figured it was a bad idea to force every List
implementation1 to implement a method that wasn't used 99.9% of the time2. This could be addressed by making the method "optional", but that has downsides too; e.g. runtime exceptions.
Because for some kinds of list (stream wrappers / adapters for example) implementing in-place reverse would be problematic. It changes the memory usage characteristics of the list by requiring it to be reified.
Also note that the generic implementation (source code) of reverse()
that is provided by Collection
uses set
to swap elements. It is close to optimal for the standard list types.
@shmosel comments:
I assume OP is asking why it wasn't added as a default method, as List.sort() was.
Good point. Possibly the 99.9% argument applies. Bear in mind that this would only help people with a codebase that is built using a Java 8 or later compilers, etc.
1 - This includes implementations in your codebase and 3rd-party libraries.
2 - 86% of statistics are made up for theatrical effect :-)
For the same reason that fill
and rotate
and shuffle
and swap
and infinitely more possible list functions aren't declared in the List
interface. They're not part of the "list" abstraction; rather, they can be implemented on top of that abstraction.
Once a List
implements the methods already in the List
interface, a reverse
function can be written on top of the List
abstraction without any knowledge of a particular List
implementation. Therefore, it would be pointless to force every class implementing List
to provide a custom implementation of reverse
(and fill
, rotate
, shuffle
, swap
, etc.).
Note: This question is a very specific case of "Why does the Collections class contain standalone (static) methods, instead of them being added to the List interface?" - one could even consider is as a duplicate. Beyond that, arguing about the reasoning behind the decision for each individual method is reading tea leaves, and nobody can tell "the reason" for the design decision for the particular case of the reverse
method (until, maybe Josh Bloch posts an answer here). Interestingly, this is a point that is not covered in the Java Collections API Design FAQ...
Some of the other answers seem convincing at the first glance, but raise other questions. Particularly, some of them don't give a reason for the design decision at all. Even if there are other ways to emulate the behavior of a certain method, or when a method is not used "99.9% of all time", it can still make sense to include it in the interface.
Looking at the List
interface, you will notice that you can basically implement all methods based on two others:
T get(int index)
int size()
(For a mutable list, you also need set
). These are exactly the ones that are still abstract in AbstractList
. So all other methods are rather "convenience" methods that can be implemented canonically, based on these two methods. In this regard, I think that the answer Sam Estep contains an important point: One could argue to implement dozens of other methods. And there would certainly be good reasons to do so. Having a look at the actual implementation of Collections#reverse(List)
:
public static void reverse(List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
What is this REVERSE_THRESHOLD
and RandomAccess
thing there? Seriously, if I felt the necessity to introduce a tagging interface like RandomAccess
, I would strongly question my design. Whenever you have a method like
void doSomethingWith(Type x) {
if (x instanceof Special) doSomethingSpecial((Special)x);
else doSomethingNormal(x);
}
then this is a strong sign that this should actually be a polymorphic method, which should be implemented accordingly for the Special
type.
So yes, it have been justified to pull the reverse
method into the interface, to allow a polymorphic implementation. The same applies to fill
rotate
, shuffle
, swap
, sort
and others. Similarly, one could have introduced a static method like
Collections.containsAll(containing, others);
that offers what is now done with the Collection#containsAll
method. But in general: The designers chose a particular set of methods that they found suitable. One of the reasonings behind leaving out certain methods may be given by one of the bottom lines of the talk about "How to Design a Good API & Why it Matters" by Joshua Bloch, one of the core designers of the Java Collections API:
When in doubt, leave it out
Interestingly, of all the methods for which a polymorphic implementation (via a method in the List
interface) could have been reasonable, one actually found its way into the interface, using a Java 8 default
method:List#sort()
. Maybe others, like reverse
, will be added later...