Lambda 식 및 일반 메서드


111

일반적인 인터페이스가 있다고 가정합니다.

interface MyComparable<T extends Comparable<T>>  {
    public int compare(T obj1, T obj2);
}

그리고 방법 sort:

public static <T extends Comparable<T>> 
       void sort(List<T> list, MyComparable<T> comp) {
    // sort the list
}

이 메서드를 호출하고 람다 식을 인수로 전달할 수 있습니다.

List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));

잘 작동합니다.

그러나 이제 인터페이스를 제네릭이 아니고 메서드를 제네릭으로 만들면 다음과 같습니다.

interface MyComparable {
    public <T extends Comparable<T>> int compare(T obj1, T obj2);
}

public static <T extends Comparable<T>> 
       void sort(List<T> list, MyComparable comp) {
}

그런 다음 다음과 같이 호출하십시오.

List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));

컴파일되지 않습니다. 람다 식에서 다음과 같은 오류를 표시합니다.

"대상 방법이 일반적 임"

좋아,을 사용하여 컴파일하면 javac다음 오류가 표시됩니다.

SO.java:20: error: incompatible types: cannot infer type-variable(s) T#1
        sort(list, (a, b) -> a.compareTo(b));
            ^
    (argument mismatch; invalid functional descriptor for lambda expression
      method <T#2>(T#2,T#2)int in interface MyComparable is generic)
  where T#1,T#2 are type-variables:
    T#1 extends Comparable<T#1> declared in method <T#1>sort(List<T#1>,MyComparable)
    T#2 extends Comparable<T#2> declared in method <T#2>compare(T#2,T#2)
1 error

이 오류 메시지에서 컴파일러가 유형 인수를 유추 할 수없는 것 같습니다. 그럴까요? 그렇다면 왜 이런 일이 발생합니까?

인터넷을 통해 다양한 방법으로 검색했습니다. 그런 다음 방법을 보여주는 이 JavaCodeGeeks 기사를 찾았 으므로 시도했습니다.

sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));

그 기사가 작동한다고 주장하는 것과는 달리 다시 작동하지 않습니다. 일부 초기 빌드에서 작동했을 가능성이 있습니다.

그래서 내 질문은 : 제네릭 메서드에 대한 람다 식을 만드는 방법이 있습니까? 메서드를 생성하여 메서드 참조를 사용하여이 작업을 수행 할 수 있습니다.

public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
    return obj1.compareTo(obj2);
}

어떤 수업에서는라고 말하고 다음 SO과 같이 전달하십시오.

sort(list, SO::compare);

답변:


117

당신은 사용할 수 없습니다 람다 식을 A에 대한 기능적인 인터페이스 의 방법 경우, 기능적인 인터페이스는 이 형식 매개 변수를 . JLS8의 섹션 §15.27.3을 참조하십시오 .

T 가 기능적 인터페이스 유형 (§9.8)이고 표현식이 [..] T의 함수 유형과 일치 하는 경우 람다 표현식은 대상 유형 T 와 호환 가능합니다 . [..] 람다 표현식은 합동입니다. 다음이 모두 참인 경우 함수 유형으로 :

  • 함수 유형에는 유형 매개 변수 가 없습니다 .
  • [..]

47
그러나이 제한은 제네릭 메서드에 대한 메서드 참조 에는 적용되지 않습니다 . 일반 기능 인터페이스가있는 일반 메소드에 대한 메소드 참조를 사용할 수 있습니다.
— Brian Goetz 2014 년

17
이 제한에 대한 타당한 이유가 있다고 확신합니다. 뭔데?
— Sandro

6
@Sandro : 람다 식에 대한 형식 매개 변수를 선언하는 구문이 없습니다. 그리고 그러한 구문은 매우 복잡합니다. 파서는 여전히 다른 합법적 인 Java 구조와는 별도로 유형 매개 변수를 사용하여 그러한 람다 표현식을 말할 수 있어야합니다. 따라서 메서드 참조에 의존해야합니다. 대상 메서드 는 설정된 구문을 사용하여 형식 매개 변수를 선언 할 수 있습니다 .
— Holger 2015

2
@Holger, 타입 매개 변수가 자동 추론 될 수있는 곳에서 컴파일러는 예를 들어 Set <?>를 선언하고 캡처 된 타입으로 타입 검사를 할 때처럼 capure 타입을 속일 수 있습니다. 물론, 본문에 유형 매개 변수로 제공하는 것이 불가능하지만, 필요하다면 메소드 참조를 사용하는 것이 좋은 대안입니다.
— WorldSEnder

17

메서드 참조를 사용하여 인수를 전달하는 다른 방법을 찾았습니다.

List<String> list = Arrays.asList("a", "b", "c");        
sort(list, Comparable::<String>compareTo);

3

컴파일러에게 적절한 버전의 일반 비교기를 지정하십시오. (Comparator<String>)

그래서 대답은

sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));


2
incompatible types: java.util.Comparator<java.lang.String> cannot be converted to MyComparable및 MyComparable일반 아니다 (어떤 유형) 그래서 (MyComparable<String>)중 하나가 작동하지 않을 것
— user85421

1
@CarlosHeuberger 코드를 어떻게 입력하고 있는지 모르겠지만 저에게는 잘 작동합니다. 이것이 제가 찾고 있던 것입니다.
— Ivan Perales M.

@IvanPeralesM. 2 개월 후 ... 코드를 복사하여 붙여넣고 정렬 줄 위의 행을 복사하여 붙여 넣었습니다. 다음과 같습니다. ideone.com/YNwBbF ! 위의 코드를 정확히 입력 하셨나요? 사용 Compartor?
— user85421 2018

아니요, 답변 뒤에있는 아이디어를 사용하여 함수를 캐스팅하여 컴파일에 어떤 유형이고 작동하는지 알려줍니다.
— Ivan Perales M.

@IvanPeralesM. 그럼 내 "타이핑"에 무슨 문제가 있습니까? 게시 된 답변은 작동하지 않습니다.
— user85421

0

당신은 다음과 같은 것을 의미합니까? :

<T,S>(T t, S s)->...

이 람다는 어떤 유형입니까? Java로 표현할 수 없으므로 함수 응용 프로그램에서이 표현식을 작성할 수 없으며 표현식을 구성 할 수 있어야합니다.

이 작업이 필요하려면 Java의 Rank2 유형 에 대한 지원이 필요합니다 .

메서드는 제네릭이 될 수 있지만 식으로 사용할 수 없습니다. 그러나 전달하기 전에 필요한 모든 제네릭 유형을 특수화하여 람다 표현식으로 줄일 수 있습니다.ClassName::<TypeName>methodName


1
"Of what type is this lambda? You couldn't express that in Java..."유형은 다른 람다와 마찬가지로 컨텍스트를 사용하여 유추됩니다. 람다의 유형은 람다 자체에서 명시 적으로 표현되지 않습니다.
— Kröw
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.