Stream.max(Integer::max) : Unexpected result

Viewed 1674

I'm studying for 1z0-809 : Java SE 8 Programmer II using Enthuware's mocktests.

Encountering this question.

List<Integer> ls = Arrays.asList(3,4,6,9,2,5,7);

System.out.println(ls.stream().reduce(Integer.MIN_VALUE, (a, b)->a>b?a:b)); //1
System.out.println(ls.stream().max(Integer::max).get()); //2
System.out.println(ls.stream().max(Integer::compare).get()); //3
System.out.println(ls.stream().max((a, b)->a>b?a:b)); //4   

Which of the above statements will print 9?

Answer is

1 and 3

But there is something else. I don't get why

System.out.println(ls.stream().max(Integer::max).get()); // PRINTS 3

I tried to debug it using peek but it doesn't help me understanding.

I tried to sort ls using Integer::max and Integer::compare

ls.sort(Integer::max);     // [3, 4, 6, 9, 2, 5, 7]
ls.sort(Integer::compare); // [2, 3, 4, 5, 6, 7, 9]

Of course, I get the fact that Integer::max is not a Comparator, hence it has the same signature of one. For me, max should be 7 in the first case since it is the last element like when I sorted with Integer::compare

Could someone break it down to something simple?

5 Answers

You need to replace

.max(Integer::max)

with

.max(Integer::compare)

The problem here is that the abstract method compare is declared to return an int value and that is also satisfied by the signature of Integer.max along with method Integer.compare in the Integer class, hence the representation Integer::max is inferred as a valid Comparator. Though the compare method is expected to be implemented such as it:

Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.

In your current scenario, the code always ends up returning a positive value (given the input) and therefore the first element in comparison is considered to be greater always and thus returned accordingly.

Although this doesn't answer the question, a possible solution to your problem would be:

try{
    int i = map.values().stream().mapToInt(e -> e).max().getAsInt();
}catch(NoSuchElementException e)
    e.printStackTrace();
}

The mapToInt(e -> e) method uses a lambda expression to transform every element in the stream to a integer value and returns a IntStream where max() method can then be called. Note that max() returns an OptionalInteger and so a getAsInt() or a orElse(0) method call is nedeed.

You can take a look at the docs for a more in-depth answer: IntStream, OptionalInt

Related