I looked at the implementation Collectors.toSet
under jdk-8 and pretty much saw the obvious thing:
public static <T> Collector<T, ?, Set<T>> toSet() {
return new CollectorImpl<>(
(Supplier<Set<T>>) HashSet::new,
Set::add,
(left, right) -> { left.addAll(right); return left; },
CH_UNORDERED_ID);
Look at combiner
the moment; this has been discussed until here , but the idea is that a combiner folds from the second argument into the first
. And this is obviously happening here.
But then I looked at the implementation jdk-9
and saw this:
public static <T> Collector<T, ?, Set<T>> toSet() {
return new CollectorImpl<>(
(Supplier<Set<T>>) HashSet::new,
Set::add,
(left, right) -> {
if (left.size() < right.size()) {
right.addAll(left); return right;
} else {
left.addAll(right); return left;
}
},
CH_UNORDERED_ID);
Now why this is happening is a little obvious - less elements to a bigger Set, then the other way around
it takes less time to add . But is it really cheaper than usual addAll
, consider the extra overhead for the branch?
It also violates my law of always folding left ...
Can someone shed some light here?