람다 식은 단일 메서드를 사용하는 익명의 내부 클래스 이상의 것입니까?


40

Java 8에서 오랫동안 기다려온 람다 식으로 새로운 과대 광고가 있습니다. 3 일마다 얼마나 멋진 지에 대한 또 다른 기사가 나타납니다.

내가 람다 식을 이해하는 한 단일 메소드 (적어도 바이트 코드 수준)를 가진 익명의 내부 클래스에 지나지 않습니다. 이것 외에도 또 다른 멋진 기능이 있습니다. 유형 추론이지만 이것과 동등한 것은 어떤 수준에서 제네릭으로 달성 할 수 있다고 생각합니다 (물론 람다 식과 같은 깔끔한 방식은 아닙니다).

이것을 알면 람다 식은 Java의 구문 설탕보다 더 많은 것을 가져올 것입니까? 현재 언어 기능으로는 만들 수없는 람다 식으로 더 강력하고 유연한 클래스 또는 다른 객체 지향 구문을 만들 수 있습니까?


30
언어가 튜링이 완료되면 이론적으로 추가 된 모든 기능을 "구문 설탕"이라고합니다.
Philipp

34
@Philipp : 잘못되었습니다. 구문 설탕의 특징은 설탕 제거가 순전히 지역적이며 프로그램의 전체 구조를 변경하지 않는다는 것입니다. 로컬 변환만으로는 구현할 수없는 많은 기능이 있습니다. 예를 들어 Java와 동일하지만 적절한 꼬리 호출을 가진 가상의 언어를 사용하는 경우 전체 프로그램을 전체적으로 변환하지 않고 꼬리 호출을 Java를 "순수하게"제거 할 수는 없습니다.
Jörg W Mittag

2
@Philipp : 불행히도 의견에 대한 단 하나의 공감대가 있습니다. 그렇지 않으면 Joerg의 의견을 1000 번 공표합니다. 아닙니다. 어떤 특징이 구문 설탕으로 묘사 될 수있는 것은 잘못입니다. 구문 설탕은 새로운 의미를 추가하지 않습니다. 실제로, AFAIK가 제안한 Java 람다는 의미가 다르기 때문에 특수 익명 내부 클래스의 구문 설탕이 아닙니다.
Giorgio

1
@ Giorgio : 그리고 다른 의미론은 무엇입니까?
user102008

2
@Giorgio : 네,하지만의 변환 this에이 OuterClass.this익명 클래스로 람다 식을 드 절임 과정의 일부입니다.
user102008

답변:


47

tl; dr : 그것은 대부분 구문 론적 설탕이지만, 더 좋은 구문은 끝없는 읽을 수없는 괄호와 괄호로 끝나는 많은 것들을 실용적으로 만듭니다.

람다는 Java보다 훨씬 나이가 들기 때문에 실제로 다른 방법 입니다. 단일 메소드를 가진 익명의 내부 클래스는 (가장 가까운) Java가 람다에 가장 가깝습니다. 그것은 얼마 동안 "충분히 좋은"근사치이지만 매우 불쾌한 구문을 가지고 있습니다.

표면적으로 Java 8 람다는 구문 설탕 이상의 것 같지 않지만 표면 아래를 보면 많은 흥미로운 추상화가 나타납니다. 예를 들어 JVM 스펙은 람다를 "true"오브젝트와 상당히 다르게 처리 하며 오브젝트가있는 것처럼 처리 할 수 있지만 JVM은이를 구현할 필요가 없습니다.

그러나 모든 기술적 인 속임수는 흥미롭고 관련성이 있지만 (JVM에서 향후 최적화가 가능하기 때문에!) 실질적인 이점은 구문 설탕 부분에 "그냥"있습니다.

더 읽기 쉬운 것 :

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

또는:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

또는 (람다 대신 메소드 핸들 사용) :

myCollection.map(String::toUpperCase);

이전에 5 줄의 코드 (3 개가 완전히 지루한 코드) 인 간결한 방식으로 마침내 표현할 수 있다는 사실은 실제적인 것 (그러나 가능한 것은 아니지만 부여 된 것) 의 실제 변화를 가져옵니다 .


1
나는 문법 당화 부분에 전적으로 동의한다. 내 질문은 람다 식으로 만 가능한 새로운 객체 지향 구문에 관한 것입니다. 모든 Java는 객체 지향 언어입니다. 제네릭과 비교할 때, Java에서 어떻게 많은 유연성을 구입했는지, 그렇지 않으면 얻을 수없는 유연성을 생각하십시오.
m3th0dman

7
@ m3th0dman : 실제로 제네릭은 새로운 능력을 추가하지 않았습니다. A List는 모든 객체를 보유 할 List<String>수 있으며 문자열 만 "만"보유 할 수 있습니다. 제네릭은 권한의 추가가 아니라 제한 (및 제한 을 공식화하는 옵션!)을 추가했습니다. Java 1.1 이후 거의 모든 것이 구문 설탕이었습니다. 그리고 이것이 반드시 나쁜 것은 아닙니다.
Joachim Sauer

3
@ m3th0dman : 실제로 제네릭은 새로운 기능을 추가하지 못했습니다. Java에서는 구문 설탕 일뿐입니다. A List<String>는 일부 반환 값 주위 ListString추가 된 캐스트 입니다. 그럼에도 불구하고 그것들은 매우 유용하고 언어를 훨씬 더 편하게 쓸 수있게 만들었습니다. 람다는 비슷한 경우입니다.
Jan Hudec

3
사실 그것은 단순한 구문 설탕 이상의 것입니다. 대부분의 기능은 invokedynamic 바이트 코드를 사용하여 JVM에서 일급 시민으로 구현됩니다. 익명의 내부 클래스로 구현되지 않았습니다.
Martijn Verburg

1
@ JanHudec : 글쎄, 그것들은 컴파일러가 실제로 그것들을 존중 하기 때문에 구문 설탕보다 약간 더 큽니다 . 런타임은 그게 사실, 그들에 대해 상관하지 않는다.
Joachim Sauer

14

Java의 경우 익명의 내부 클래스를 만드는 더 좋은 방법 일뿐입니다. 이것은 자바에서 모든 바이트 코드의 비트가 특정 클래스 내에 있어야한다는 근본적인 결정 때문입니다. 수십 년의 레거시 코드를 고려한 후에는 변경할 수 없습니다.

그러나 람다식이 실제로는 아닙니다. 밴드 워크에 뒤틀림이 아닌 고유의 개념 인 형식주의에서 람다는 기본 구성 요소입니다. 그들의 구문과 사람들에 대한 사람들의 태도는 매우 다릅니다. 컴퓨터 프로그램의 구조와 해석 에서 람다만으로 만들어진 익명의 재귀 함수의 예는 전체 계산 개념을 바꿀 수 있습니다. (그러나, 프로그램 학습 방법은 주류 성공 스토리가되기 위해 난해한 것임을 확신합니다.)


1
람다 측면에서 모든 것을 구현할 수 있다는 것을 배우는 것은 매우 유익하며 내 생각에는 "비평 적"이 아닙니다. (그러나 대부분의 "코더"는 흥미로운 CS 이론에 관심이 없다고 생각합니다.) 람다는 특별한 것이 아닙니다. 그것은 람다는 보편적 인 구성의 한 유형이라는 것을 의미합니다. SKI 결합기와 같은 다른 것들도 있습니다. 람다는 기능적 패러다임의 기본 구성 요소이지만 다른 패러다임의 기본 요소 일 수도 있습니다.
user102008

"대역폭 왜건 왜곡"에 +1 : 일부 언어가 다른 인기있는 언어를 모방하기 위해 왜 계속 바뀌는 지, 프로그래머가 왜 그 언어를 사용하는지 궁금합니다. 나는 람다를 좋아하고 스칼라, Lisp, Haskell에서 많이 사용하지만 Java 또는 C ++에서는 다른 언어에서 인기가 있기 때문에 언어에 사후 생각처럼 느껴집니다.
Giorgio

2

그렇습니다. 그것은 람다를 쓰는 곳이라면 어디에서나 람다의 맥락에 대해 추론 된 기능적 인터페이스를 구현하는 한 가지 방법으로 익명의 내부 클래스 표현식으로 해당 표현식을 다시 작성할 수 있다는 의미에서 구문 설탕 일뿐입니다. 의미 적 으로 정확히 동일합니다. 그리고 다른 표현식이나 코드 줄을 변경하지 않고 단순히 람다 식을 익명 클래스 식으로 바꾸면됩니다.


1
왜 downvote? 내가 말한 것은 완전히 정확합니다
user102008

작성한 내용은 Java 람다에 대한 합리적인 제안이지만,이 제안은 다른 제안 ( doanduyhai.wordpress.com/2012/07/12/… ) 을 위해 폐기되었습니다 .
Giorgio

1
@Giorgio : 나는 아무것도 "제안"하지 않습니다. 내가 한 말에 정확히 동의하지 않습니까? 예, 표현식 내부가 다르게 보일 것입니다. 예를 들어 메소드를 추가 할 것입니다. 예, this로 변환해야 OuterClass.this합니다. 그것은 내가 말한 것과 모순되지는 않는다. 모든 람다 표현 은 그 표현 밖의 어떤 것도 변경하지 않고 의미 적으로 동등한 익명 클래스 표현 으로 변환 될 수있다 . 나는 내부가 변하지 않을 것이라고 말하지 않았다.
user102008

3
당신이 말한 내용이 잘못되었습니다. lambda와 anon 내부 클래스의 의미는 정확히 동일 하지는 않습니다 (비슷하지만). 내 머리 꼭대기 에서이 의미의 의미가 바뀝니다. anon 내부 클래스는 항상 객체의 새로운 인스턴스를 생성하지만 람다는 수도 있고 그렇지 않을 수도 있습니다.
스튜어트 마크

1
@StuartMarks : 아니요, 내 대답을 읽지 못했습니다. 나는 그들 각자가 다른 모든 것을 할 수 있다고 말하지 않았습니다. 나는 람다는 의미 적으로 동일한 동등한 익명 클래스를 가지고 있다고 말했다. 내가 이미 언급했듯이 this람다는 구문 설탕의 일부이며 의미론의 차이가 아닙니다. 구현의 차이점, 구현! = 의미론. 객체 아이덴티티의 차이점 객체 아이덴티티는 람다의 기능성에 매우 중요합니다. 람다 / 아논 클래스의 객체 아이덴티티는 유용하지 않기 때문에 아무도 확인하지 않습니다.
user102008

1

Joachim Sauer는 이미 귀하의 질문에 대한 답변을 훌륭하게 수행했지만 중요하다고 생각하는 것을 암시했습니다. Lambdas는 클래스가 없으므로 컴파일되지 않습니다. 모든 익명의 내부 클래스는 .class 파일을 생성하며이 클래스 파일은 ClassLoader에 의해로드되어야합니다. 따라서 Lambdas를 사용하면 코드를 더 아름답게 만들 수있을뿐만 아니라 컴파일 된 코드의 크기, ClassLoader의 메모리 공간 및 하드 드라이브에서 비트를 전송하는 데 걸리는 시간도 줄어 듭니다.


-1

아뇨.

그것을 람다로 넣는 또 다른 방법은 객체 지향적이지 않지만 간결하고 익명 클래스 또는 선호하는 내부 클래스가 객체 지향 방식으로 달성하는 것과 동일한 것을 달성하는 방법입니다.


1
함수형 프로그래밍은 객체 지향 프로그래밍과 완전히 직교 할 수 있습니다 (스칼라 및 F # 참조). 이것은 단순히 함수형 프로그래밍을 원칙적으로 싫어하는 누군가의 의견과 같습니다.
KChaloux 2016 년

1
@KChaloux-함수형 프로그래밍 증오가 아닙니다. 해머 드라이버보다는 망치와 드라이버를 선호하는 사람이 답을 작성합니다. OO 프로그래밍은 기능적 프로그래밍과 마찬가지로 좋은 패러다임입니다. 언어를 선호하는 것은 언어의 의도를 명확하게하는 것입니다. 람다 나는 Java의 다른 OO 본성을 진흙으로 느낀다. Java는 기능적 언어로 설계되지 않았습니다. 인간은 최선을 다하기 위해 구조가 필요합니다.
Guido Anselmi 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.