List class in Java 8 has a new method sort
added to it. Could anyone please clarify when should I prefer to use this as opposed to Collections.sort(..)
method?
There is no functional difference because Collections.sort(list)
calls list.sort(null)
and Collections.sort(list, comparator)
calls list.sort(comparator)
.
So it's just a matter of style - when providing your own comparator, calling sort on the list is probably more natural and readable than using an external static method.
However if you just want to sort the list in natural order, Collections.sort(list)
is maybe clearer than list.sort(null)
.
You should go for List.sort
.
Example of using List.sort
, to sort a list of String with respect to the length of the elements:
List<String> list = new ArrayList<>(Arrays.asList("aa", "aaa", "a"));
list.sort(comparing(String::length));
Collections.sort()
was the pre-Java 8 way of doing this. Note that there is no real difference between the two. If you take a look at Collections.sort
source code, you can notice that it calls list.sort
:
public static <T extends Comparable<? super T>> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
Though you can use the List.sort(Comparator)
method, the main purpose of this method is overriding. Before Java-8 the sorting of every List
was somewhat ineffective. First the list was dumped into array via toArray()
method, then the array was sorted and finally the list was updated via ListIterator.set
. In Java-8 this is the default behavior implemented in List.sort(Comparator)
default method. However you may change it in subclasses if you can provide more efficient algorithm. Examples:
ArrayList
and Arrays.asList()
provide own sort
implementation which directly sorts the internal array, thus you don't need to copy back and forth.
CopyOnWriteArrayList
just can be sorted now! Try the following code:
List<String> list = new CopyOnWriteArrayList<>(Arrays.asList("a", "c", "b"));
Collections.sort(list);
In Java-7 it throws UnsupportedOperationException
, because supporting ListIterator.set
contradicts the idea of this list (every iterator iterates the independent snapshot). In Java-8 the ListIterator.set
is still unsupported, but this code works correctly due to custom sort implementation.
Collections.singletonList
and Collections.emptyList
just do nothing (sorting 0 or 1 element is a no-op) which is certainly faster than creating a one-element or zero-element array, sort it and iterate over list to set the value back.
Collections.unmodifiableList
now just throws UnsupportedOperationException
. Prior to Java-8 you got the exception only after dumping the immutable list to the array, sorting the array and starting to write it back.
Here's an example which may be useful in user code. Suppose that you want to create a mapped view of some list:
public class MappedList<T, R> extends AbstractList<R> {
private final List<T> source;
private final Function<? super T, ? extends R> mapper;
public MappedList(List<T> source, Function<? super T, ? extends R> mapper) {
this.source = source;
this.mapper = mapper;
}
@Override
public R get(int index) {
return mapper.apply(source.get(index));
}
@Override
public int size() {
return source.size();
}
}
Example usage:
List<String> list = Arrays.asList("a", "foo", "bb", "bar", "qq");
List<Integer> mappedList = new MappedList<>(list, String::length);
System.out.println(mappedList); // prints [1, 3, 2, 3, 2]
Works fine, but trying Collections.sort(mappedList);
you will get UnsupportedOperationException
(set
operation does not work as you cannot reverse the mapping function). However if you implement the sort()
method in MappedList
, you will be able to sort it correctly (changing the original list):
@Override
public void sort(Comparator<? super R> c) {
@SuppressWarnings("unchecked")
Comparator<? super T> comparator = c == null ?
Comparator.comparing((Function<? super T, ? extends Comparable<Object>>) mapper) :
Comparator.comparing(mapper, c);
source.sort(comparator);
}
List<String> list = Arrays.asList("a", "foo", "bb", "bar", "qq");
List<Integer> mappedList = new MappedList<>(list, String::length);
Collections.sort(mappedList);
System.out.println(mappedList); // prints [1, 2, 2, 3, 3]
System.out.println(list); // prints [a, bb, qq, foo, bar]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With