Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there no "List.reverse()" method in Java?

In Java, to reverse elements in a List, I need to use:

Collections.reverse(list)

I was just wondering why Java doesn't implement the reverse method within the List interface so that I could do the in-place reverse like this:

list.reverse()

Does anyone have any ideas about this?

like image 329
Hanfei Sun Avatar asked Jun 18 '16 12:06

Hanfei Sun


People also ask

Can you reverse a list in Java?

reverse() method is a java. util. Collections class method. It reverses the order of elements in a list passed as an argument.

How do you reverse a list in Java Stream?

The first approach would be to collect() the stream into a list - and then use the Collections. reverse() method on the list, which reverses it in-place. Note: If you also want to sort the collection while reversing it, you can use the sorted(Comparator. reverseOrder()) method in the chain.

How do you reverse a collection list?

In short, to reverse the order of a List you should: Create a new ArrayList. Populate the list with elements, with the add(E e) API method of the ArrayList. Reverse the elements of the list, invoking the reverse(List list) API method of the Collections.


2 Answers

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...

like image 116
Marco13 Avatar answered Oct 05 '22 17:10

Marco13


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 :-)

like image 24
Stephen C Avatar answered Oct 05 '22 19:10

Stephen C