Java 8의 형식 유추


30

Java 8에서 새로운 람다 표기법 (예 : 이 기사 참조 )을 도입하려면 일종의 유형 유추가 필요합니까?

그렇다면 새로운 유형의 시스템이 Java 언어 전체에 어떤 영향을 미칩니 까?

답변:


47

래칫 괴물의 답변 과 주석 스레드 에는 잘못된 정보가 많이 있습니다. 댓글이 너무 작기 때문에 여기에 답변 해 드리겠습니다. 또한 이것은 결국 답변이므로 원래 질문에도 대답하려고합니다. (그러나 나는 타입 시스템 전문가가 아닙니다.)

첫째, 원래 질문에 대한 짧은 대답은 예와 아니오입니다. 예, Java 8은 Java 7보다 상당히 많은 유형 유추를 갖습니다. 아니요, 약간의 변경 사항이 있지만 Java 8에는 "새로운"유형 시스템이 없습니다. .

Java 8은 여전히 ​​정적으로 입력되며 클래스와 인터페이스 사이에 이분법이 있습니다. 함수 유형과 같은 새로운 유형은 없습니다. 람다의 유형은 본질적으로 하나의 추상적 인 방법을 가진 일반적인 인터페이스 인 "기능적 인터페이스"이다.

인터페이스는 이제 기본 메소드 형태의 코드를 가질 수 있지만 클래스의 단일 상속 모델과 여러 인터페이스의 상속 모델은 동일하게 유지됩니다. 물론 기본 메소드가있는 경우 메소드 분석 규칙과 같은 일부 조정이 있지만 기본 사항은 변경되지 않습니다.

형식 유추로 유추되는 모든 형식은 명시 적으로 작성할 수 있습니다. 래칫 괴물 의 예 를 사용하려면

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

기본적으로 설탕입니다

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

따라서 sparkleshy 의 진술 "유형 추론은 유형 시스템의 확장이 필요하지 않습니다"는 기본적으로 정확합니다.

그러나 구문 설탕으로 돌아 가기 위해 람다 표현이 익명의 내부 클래스의 구문 설탕이 아니라는 진술을 반복 합니다. 래칫 괴물은 람다 표현이 익명의 내부 클래스 인스턴스화로 번역되었다고 스파클시는 단순히 람다 익명의 내부 클래스에 대한 구문 설탕 이라고 단언 했지만, 이러한 진술은 틀렸다. 오래된 정보를 기반으로합니다. 초기 람다 구현은 이런 식으로 람다를 구현했지만 상황이 변경되었습니다.

Lambda 식은 내부 클래스와 의미 적으로 다르며 내부 클래스와 다르게 구현됩니다.

람다 식은 몇 가지면에서 내부 클래스와 의미 적으로 다릅니다. 람다 식을 평가할 때마다 새 인스턴스를 만들 필요는 없습니다. 또한 서로 다른 캡처 의미론을 가지고 있습니다. 예를 들어, 이들은 다르게 캡처 합니다 . 내부 클래스에서, 이는 람다있는 반면, 내부 클래스 인스턴스 이것은 둘러싸 인스턴스이다. 다음을 고려하세요:

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

최근 JDK 8 람다 빌드 ( b69 사용 )에서 출력은 다음과 같습니다.

CaptureThis$1@113de03
outer

또한 람다 식은 내부 클래스와 완전히 다르게 구현됩니다. 디스 어셈블 된 출력을 비교하면 내부 클래스 코드가 생성으로 직접 컴파일되고 CaptureThis $ 1의 생성자를 호출하는 반면 람다 식은 지정되지 않은 수단을 통해 Runnable을 조달하는 invokedynamic 명령으로 컴파일됩니다. 작동 방식 및 이유에 대한 자세한 설명은 Brian Goetz의 JavaOne 2012 talk Lambda : A Peek Under The Hood를 참조하십시오 .


2
".. 그들은 다른이를 캡처 내부 클래스에서,이 람다에있는 반면,이 둘러싸는 인스턴스 인, 내부 클래스의 인스턴스 다음 사항을 고려하십시오"여전히 대체하여 문법 설탕을 수행 할 수 있습니다 this으로MyClass.this
래칫 괴물

4
어셈블러를 넘어서는 모든 것 (그리고 때로는 그조차도)은 틀림없이 구문 설탕입니다. 그러나 람다는 내부 클래스의 구문 설탕 이 아닙니다 (더 이상). 그들은 비슷한 목표를 달성하고 약간의 유사점을 가지고 있지만, 후드 아래에서 (관측 적으로) 다릅니다.
Joachim Sauer

1
"람다 식은 의미 적으로 내부 클래스와 다르며 내부 클래스와 다르게 구현됩니다.": 매우 좋은 설명 (+1)에 감사합니다. 나에게 분명하지 않은 것은 람다는 특수 익명 클래스의 구문 설탕으로 구현되지 않았습니까? 즉, 새로운 의미론에 의해 도입 된 추가 복잡성의 이점은 무엇입니까? 익명의 내부 클래스로는 해결할 수없는 문제는 무엇입니까? (그러나 나는 여전히 당신이 게시 한 링크를 봐야 할 것입니다. 아마도 거기에서 답을 찾을 것입니다.)
Giorgio

1
@Joachim Sauer : 구문 의미 설탕을 기존 의미론의 새로운 구문으로 생각합니다. 새로운 의미론이 도입되면 구문 설탕에 대해 말할 수 없다고 생각합니다. 이런 의미에서 나는 어셈블러 이외의 모든 것이 구문 설탕이라고 주장 할 수 있다고 생각하지 않습니다.
Giorgio

3
@Giorgio : 람다는 왜 익명의 내부 클래스에 대한 구문 설탕이 아닌지에 대해 이것에 대해 큰 토론이있었습니다. 브라이언 게츠의이 메일이 결정을 요약 mail.openjdk.java.net/pipermail/lambda-dev/2011-August/... . TL; DR 미래의 진화를위한 문을 열어두고 오늘날 우리는 더 나은 성능을 얻습니다. Goetz는 실제로 관련 질문에 답변하고 있습니다. 람다 객체입니까? 그러나 대답이 '아니요'이거나 '아마도'라면 내면의 수업에는 설탕이 될 수 없습니다.
Stuart Marks
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.