This is my code
List ints = Stream.of(1,2,4,3,5).collect(Collectors.toList());
Integer maxInt = ints.stream()
This function (note ->
is for closures and not to be confused with =>
which is for comparison)
i -> i
just means you need to compare the entire object as it is. i.e. if I have an i
you need to compare i
A less trivial example might be
max(Comparator.comparing(i -> -i))
which will give you the minimum or
max(Comparator.comparing(i -> Math.abs(100-i))
gives you a value which is farthest from 100.
max(Comparator.comparing(i -> i.toString()))
which will give you the maximum comparing as a String i.e. "9" > "10" as a string.
Comparator.comparing
expects a function which maps the source object to the value which actually gets compared - in your case, as you don't want to pre-process the value to be compared, i
is simply mapped to itself.
The method Comparator.comparing(…)
is intended to create a Comparator
which uses an order based on a property of the objects to compare. When using the lambda expression i -> i
, which is a short writing for (int i) -> { return i; }
here, as a property provider function, the resulting Comparator
will compare the values itself. This works when the objects to compare have a natural order as Integer
has.
So
Stream.of(1,2,4,3,5).max(Comparator.comparing(i -> i))
.ifPresent(maxInt->System.out.println("Maximum number in the set is " + maxInt));
does the same as
Stream.of(1,2,4,3,5).max(Comparator.naturalOrder())
.ifPresent(maxInt->System.out.println("Maximum number in the set is " + maxInt));
though the latter is more efficient as it is implemented as singleton for all types which have a natural order (and implement Comparable
).
The reason why max
requires a Comparator
at all, is because you are using the generic class Stream
which might contain arbitrary objects.
This allows, e.g. to use it like streamOfPoints.max(Comparator.comparing(p->p.x))
to find the point with the largest x
value while Point
itself does not have a natural order. Or do something like streamOfPersons.sorted(Comparator.comparing(Person::getAge))
.
When using the specialized IntStream
you can use the natural order directly which is likely to be more efficient:
IntStream.of(1,2,4,3,5).max()
.ifPresent(maxInt->System.out.println("Maximum number in the set is " + maxInt));
To illustrate the difference between “natural order” and a property based order:
Stream.of("a","bb","aaa","z","b").max(Comparator.naturalOrder())
.ifPresent(max->System.out.println("Maximum string in the set is " + max));
this will print
Maximum string in the set is z
as the natural order of String
s is the lexicographical order where z
is greater than b
which is greater than a
On the other hand
Stream.of("a","bb","aaa","z","b").max(Comparator.comparing(s->s.length()))
.ifPresent(max->System.out.println("Maximum string in the set is " + max));
will print
Maximum string in the set is aaa
as aaa
has the maximum length of all String
s in the stream. This is the intended use case for Comparator.comparing
which can be made even more readable when using method references, i.e. Comparator.comparing(String::length)
which almost speaks for itself…