The fact that interfaces can define
default methods allowed the JDK authors to make a large number of additions to
the collection API interfaces. Default implementations for these are provided
on all the core interfaces, and more efficient or well-behaved overridden
implementations were added to all the concrete classes, where applicable.
Here's a list of the new methods:
- Iterable.forEach(Consumer)
- Iterator.forEachRemaining(Consumer)
- Collection.removeIf(Predicate)
- Collection.spliterator()
- Collection.stream()
- Collection.parallelStream()
- List.sort(Comparator)
- List.replaceAll(UnaryOperator)
- Map.forEach(BiConsumer)
- Map.replaceAll(BiFunction)
- Map.putIfAbsent(K, V)
- Map.remove(Object, Object)
- Map.replace(K, V, V)
- Map.replace(K, V)
- Map.computeIfAbsent(K, Function)
- Map.computeIfPresent(K, BiFunction)
- Map.compute(K, BiFunction)
- Map.merge(K, V, BiFunction)
- Map.getOrDefault(Object, V)
Also, Iterator.remove() now has a default,
throwing implementation, which makes it slightly easier to define unmodifiable
iterators.
Collection.stream() and Collection.parallelStream() are the main gateways into the
stream API. There are other ways to generate streams, but those are going to be
the most common by far.
The addition of List.sort(Comparator) is fantastic. Previously, the way to sort an ArrayList was this:
Collections.sort(list, comparator);
That code, which was your only option
in Java 7, was frustratingly inefficient. It would dump the list into an array,
sort the array, then use a ListIterator to insert the array contents into the
list in new positions.
The default implementation of
List.sort(Comparator) still does this, but concrete implementing classes are
free to optimize. For instance, ArrayList.sort invokes Arrays.sort on the
ArrayList's internal array. CopyOnWriteArrayList does the same.
Performance isn't the only potential
gain from these new methods. They can have more desirable semantics, too. For
instance, sorting a Collections.synchronizedList() is an atomic operation using
list.sort. You can iterate over all its elements as an atomic operation using
list.forEach. Previously this was not possible.
Map.computeIfAbsent makes working with multimap-like structures easier:
// Index strings by length:
Map<Integer, List<String>> map = new HashMap<>();
for (String s : strings) {
map.computeIfAbsent(s.length(),
key -> new ArrayList<String>())
.add(s);
}
// Although in this case the stream API
may be a better choice:
Map<Integer, List<String>> map =
strings.stream()
.collect(Collectors.groupingBy(String::length));
No comments:
Post a Comment