0

I have one List<List> I want to sort it according to column . I used the following code.

    // data is List<List<String>>
    data.sort(Comparator.comparing(e-> e.get(col)));                

Its working and sorting according column specified. But If I used reversed() or thenComparing() method, It says

error: cannot find symbol
                    data.sort(Comparator.comparing(e-> e.get(col)).reversed()  );
                                                        ^
  symbol:   method get(int)
  location: variable e of type Object

Also with the thenComparing method,

error: cannot find symbol
                    data.sort(Comparator.comparing(e-> e.get(col)).thenComparing(e->e.get(col2))  );
                                                        ^
  symbol:   method get(int)
  location: variable e of type Object

error: cannot find symbol
                    data.sort(Comparator.comparing(e-> e.get(col)).thenComparing(e->e.get(col2))  );
                                                                                     ^
  symbol:   method get(int)
  location: variable e of type Object
2 errors

I'm not getting anything from the error messages. Fyi, Im using OpenJDK 11 for this.

  • Can you show us minimal reproducible code ? – Eklavya Aug 07 '20 at 09:52
  • I have a List> with some data then I'm sorting it. then just printing it to the console. –  Aug 07 '20 at 09:53
  • 1
    See [java - comparing and thenComparing gives compile error - Stack Overflow](https://stackoverflow.com/questions/40500280/comparing-and-thencomparing-gives-compile-error). –  Aug 07 '20 at 09:53
  • 1
    You need to specify the type in the lambda argument. `(List e )-> e.get(0)` – matt Aug 07 '20 at 09:56
  • Yes @saka1029 your comment solved my problem –  Aug 07 '20 at 09:56

1 Answers1

3

Seems like java doesn't infer the type once you have a second layer.

In the first example.

data.sort( Comparator.comparing( e-> e.get(0) ) );

The type is inferred from data, but in the second example.

data.sort( Comparator.comparing( e-> e.get(0) ).reversed() );

The type of 'comparing' is not inferred. You can resolve this a couple ways, the easiest to be explicit.

data.sort( Comparator.comparing( (List<String> e) -> e.get(0) ).reversed() );

It seems funny that java doesn't chain inferences. If we include the intermediate step of creating the comparator, we can see pretty clearly it doesn't.

Comparator<List<String>> c = Comparator.comparing( e-> e.get(0) ).reversed();

| Error: | cannot find symbol
| symbol: method get(int)
| Comparator<List> c = Comparator.comparing( e->e.get(0) ).reversed();
| ^---^
| Error:
| incompatible types: java.util.Comparator<java.lang.Object> cannot be converted to java.util.Comparator<java.util.List<java.lang.String>>
| Comparator<List> c = Comparator.comparing( e->e.get(0) ).reversed();
| ^--------------------------------------------^

Now we get two errors, one in the lambda because the argument is an Object, and the second error because we're creating a Comparator<Object>.

I'm thinking it works this way, but I'm not sure how to verify. 'reversed' will take the type argument of the instance calling it, the type is not inferred. By the time 'reversed' is called the object has to have been instantiated and the generic assigned. The call to comparing then has no upper bounds, it just has to return a Comparator<?>.

An alternative solution, specify the types when the Comparator is called.

Comparator<List<String>> c = Comparator.<List<String>, String>comparing( e->e.get(0) ).reversed();
matt
  • 10,892
  • 3
  • 22
  • 34
  • 2
    Or `Comparator.comparing(e -> e.get(0), Comparator.reverseOrder())`. Or `Collections.reverseOrder(Comparator.comparing(e -> e.get(0)))`. Generally, anything that nests method calls instead of chaining them. Otherwise, you need explicit types. – Holger Aug 07 '20 at 13:53