简体   繁体   中英

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?

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 implementation 1 to implement a method that wasn't used 99.9% of the time 2 . This could be addressed by making the method "optional", but that has downsides too; eg 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.).

Because Collection is an utilitarian class, that actually based on one of SOLID principle :
S - Single Responsibility Principle

This principle states that if we have 2 reasons to change for a class, we have to split the functionality in two classes.

You have a class that play a some role, and if you need to manipulate of inner data you need to create some subsidiary class, that will plays another role.

If you need list.reverse() you need to use Eclipse Collections , when you can use just list.reverseThis() , see this . In JDK list, a lot of method (like sort, max, min) does not be added.

It's two different ways of API design:

  1. A lot of method in Collection -> rich collection -> Eclipse Collections, drawback : a lot of rarely used method in List,
  2. Only most used method and Utility class -> JDK collection, drawback : need to use Utility class like Collections,

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

Reverse is defined in Collections (with an extra (s)). This is not a part of collection hierarchy, rather it has been given as a part of utility class which can be used for different Lists.

Reversing a list is not a key part of defining a list , so its kept out of interface and given separately. If defined in the interface, everyone will have to implement it, which may not be suitable for all.

The makers of collection could have build this in List hierarchy as well, ( Since most list derivations have an abstract class in between, they could have put it in any abstract class in between). However, to simplify everyone's life it makes sense to keep it in single utility class so that we don't have to figure out which class to look for all collection related utility functions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM