krzyk krzyk - 5 months ago 19
Java Question

Sorting array with streams using reversed comparator

I want to sort an array which has two columns using a comparator on the second column and reverse the order.

The array is:

String[][] names = {{"a", "1234"}, {"b", "12312"}, {"c", "43"}};


And to return the sorted array I use:

String[][] out = Arrays.stream(names)
.sorted(
Comparator.comparing(x -> x[1])
)
.toArray(String[][]::new);


Which works well, but when I try to reverese the order of sort by using
reversed()
:

String[][] out = Arrays.stream(names)
.sorted(
Comparator.comparing(x -> x[1]).reversed()
)
.toArray(String[][]::new);


I get error:

Error:(44, 66) java: array required, but java.lang.Object found


And my IDE highlights the x in the
x[1]
part. What I'm doing wrong?

Answer

The compiler is not able to infer the generic type parameters to comparing() when you add the .reversed() chain call, so you have to explicitly give them.

First, you need to be aware of the full declaration of comparing():

static <T,U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor)

It has two type parameters:

  • T - The input to the function (lambda), i.e. String[] in your case
  • U - The return value of the function, i.e. String in your case

So you can write:

Comparator.<String[], String>comparing(x -> x[1]).reversed()

Alternatively, you can just specify the parameter type in your lambda (i.e. T), and the compiler will infer U.

Comparator.comparing((String[] x) -> x[1]).reversed()

That's probably the way you'd want to do it.


You can also do either of those to the first one, if you like. These are all the same, just becoming more and more explicit:

Comparator.comparing(x -> x[1])
Comparator.comparing((String[] x) -> x[1])
Comparator.<String[], String>comparing(x -> x[1])
Comparator.<String[], String>comparing((String[] x) -> x[1])