Comparator.reversed ()는 람다를 사용하여 컴파일되지 않습니다.


111

일부 사용자 개체가있는 목록이 있고 목록을 정렬하려고하지만 메서드 참조를 사용하여 작동하며 람다 식을 사용하면 컴파일러에서 오류가 발생합니다.

List<User> userList = Arrays.asList(u1, u2, u3);
userList.sort(Comparator.comparing(u -> u.getName())); // works
userList.sort(Comparator.comparing(User::getName).reversed()); // works
userList.sort(Comparator.comparing(u -> u.getName()).reversed()); // Compiler error

오류:

com\java8\collectionapi\CollectionTest.java:35: error: cannot find symbol
            userList.sort(Comparator.comparing(u -> u.getName()).reversed());
                                                     ^
symbol:   method getName()
location: variable u of type Object
1 error

답변:


145

이것은 컴파일러의 유형 추론 메커니즘의 약점입니다. u람다 의 유형을 추론하려면 람다의 대상 유형 을 설정해야합니다. 이것은 다음과 같이 수행됩니다. userList.sort()유형의 인수가 필요합니다 Comparator<User>. 첫 번째 줄에서 Comparator.comparing()를 반환해야합니다 Comparator<User>. 이것은 그 의미 Comparator.comparing()필요 Function소요 User인수를. 따라서 첫 번째 줄의 람다에서 u유형이어야 User하며 모든 것이 작동합니다.

두 번째 및 세 번째 줄에서에 대한 호출의 존재로 인해 대상 입력이 중단됩니다 reversed(). 나는 그 이유를 완전히 모르겠습니다. 수신자와 반환 유형이 reversed()모두 Comparator<T>있으므로 대상 유형이 수신자에게 다시 전파되어야하는 것처럼 보이지만 그렇지 않습니다. (내가 말했듯이 약점이다.)

두 번째 줄에서 메서드 참조는이 간격을 채우는 추가 유형 정보를 제공합니다. 컴파일러를 추론이 때문에이 정보는, 세 번째 줄에서 부재 uObject실패 (최후의 추론 대체).

분명히 메서드 참조를 사용할 수 있다면 그렇게하면 작동합니다. 예를 들어 추가 매개 변수를 전달하려는 경우와 같이 메서드 참조를 사용할 수없는 경우가 있으므로 람다 식을 사용해야합니다. 이 경우 람다에 명시 적 매개 변수 유형을 제공합니다.

userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());

향후 릴리스에서이 경우를 다루기 위해 컴파일러를 향상시킬 수 있습니다.


28
Lambda는 암시 적 유형 (매개 변수에 대한 매니페스트 유형 없음)과 명시 적 유형 으로 나뉩니다 . 메서드 참조는 정확 (오버로드 없음)과 부정확 으로 나뉩니다 . 수신자 위치의 제네릭 메서드 호출에 람다 인수가 있고 형식 매개 변수를 다른 인수에서 완전히 추론 할 수없는 경우 명시 적 람다, 정확한 메서드 참조, 대상 형식 캐스트 또는 명시 적 형식 감시를 ​​제공해야합니다. 계속하는 데 필요한 추가 유형 정보를 제공하기위한 일반 메소드 호출.
Brian Goetz

1
@StuartMarks, 컴파일러가 이와 같이 작동하는 "이유를 완전히 확신하지 못합니다". 그러나 언어 사양 은 무엇을 말합니까? 언어 사양에 따라 제네릭 유형을 결정하는 데 충분한 정보가 있어야합니까? 그렇다면 이것은 컴파일러 버그이며 그에 따라 제출하고 처리해야합니다. 그렇지 않으면 Java 언어가 개선되어야하는 영역입니다. 무엇 이니?
Garret Wilson

8
문제의 사양을 작성 했으므로 Brian의 의견을 확실하게 다룰 수 있다고 생각합니다. :-)
minimalis

1
슬프게도 이것 중 어느 것도 반전으로 작동하지 않는 동안 반전없이 작동하는 이유를 설명하지 않습니다.
Chris311

90

두 번째 인수로 Comparator.comparingwith 두 인수 를 사용하여이 제한을 해결할 수 있습니다 Comparator.reverseOrder().

users.sort(comparing(User::getName, reverseOrder()));

4
좋은. 명시 적으로 형식화 된 람다를 사용하는 것보다 더 좋습니다. 또는 더 나은 방법은 users.sort(reverseOrder(comparing(User::getName)));.
rolve

10
reverseOrder(Comparator<T>)위 의 방법은에있는 java.util.Collections것이 아니라에 Comparator있습니다.
롤백
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.