구문 설명
람다 표현은 다음 부분으로 구성됩니다.
1. 괄호 안의 공식 매개 변수 목록. Checkperson.test 메소드에는 Person 클래스의 인스턴스를 나타내는 매개 변수 p가 포함되어 있습니다. 참고 : Lambda 표현식의 매개 변수 유형은 생략 될 수 있습니다. 또한 매개 변수가 하나만 있으면 괄호를 생략 할 수 있습니다. 예를 들어, 이전 섹션에서 언급 된 코드는 다음과 같습니다.
p-> p.getgender () == person.sex.male && p.getage ()> = 18 && p.getage () <= 25
2. 화살표 기호 : ->. 매개 변수와 기능 본체를 분리하는 데 사용됩니다.
3. 기능 본문. 표현식 또는 코드 블록으로 구성됩니다. 이전 섹션의 예 에서이 표현식이 사용되었습니다.
p.getgender () == person.sex.male && p.getage ()> = 18 && p.getage () <= 25
표현식을 사용하는 경우 Java 런타임은 표현식 값을 계산하고 반환합니다. 또한 코드 블록에서 리턴 명령문을 사용하도록 선택할 수도 있습니다.
p-> {return p.getgender () == person.sex.male && p.getage ()> = 18 && p.getage () <= 25; }그러나 반환 명령문은 표현이 아닙니다. Lambda 표현에서, 성명서는 Curly Braces로 둘러싸여 있어야하지만, 빈 반환 값이있는 메소드를 호출 할 때 Curly Braces의 진술을 동봉 할 필요는 없으므로 다음 쓰기 방법도 정확합니다.
이메일 -> system.out.println (이메일)
Lambda 표현 및 방법 선언에는 많은 유사점이 있습니다. 따라서 Lambda 표현식은 익명 방법, 즉 이름 정의가없는 방법으로 간주 될 수 있습니다.
위에서 언급 한 Lambda 표현식은 하나의 매개 변수를 공식 매개 변수로만 사용하는 표현식입니다. 다음 예제 클래스 인 Caulator는 여러 매개 변수를 공식 매개 변수로 사용하는 방법을 보여줍니다.
package com.zhyea.zytools; public class calculator {인터페이스 integermath {int operation (int a, int b); } public int operationBinary (int a, int b, integermath op) {return op.operation (a, b); } public static void main (String ... args) {calculator myapp = new Calculator (); integermath 추가 = (a, b) -> a + b; System.out.println ( "40 + 2 =" + MyApp.operateBinary (40, 2, addite)); System.out.println ( "20-10 =" + myapp.operatebinary (20, 10, subtraction)); }}코드의 OperatingBinary 메소드는 두 개의 정수 매개 변수를 사용하여 산술 작업을 수행합니다. 여기서 산술 작업 자체는 Integermath 인터페이스의 예입니다. 위의 프로그램에서는 Lambda 표현식을 사용하여 두 개의 산술 작업이 추가 및 뺄셈을 정의합니다. 프로그램 실행은 다음 내용을 인쇄합니다.
40 + 2 = 4220-10 = 10
외부 클래스의 로컬 변수에 액세스합니다
Lambda Expressions는 지역 클래스 또는 익명 수업과 유사하게 외부 클래스의 로컬 변수에 액세스 할 수 있습니다. 차이점은 Lambda 표현식을 사용할 때 재정의와 같은 문제를 고려할 필요가 없다는 것입니다. Lambda 표현은 어휘 개념 일뿐입니다. 즉, 슈퍼 클래스에서 이름을 물려받을 필요가 없으며 새로운 스코프를 소개하지도 않습니다. 즉, 람다 표현의 선언은 외부 환경에서 선언과 동일한 의미를 갖습니다. 이것은 다음 예에서 보여줍니다.
패키지 com.zhyea.zytools; import java.util.function.consumer; public class lambdascopetest {public int x = 0; 클래스 FirstLevel {public int x = 1; void methodinFirstRevel (int x) {// 다음 문장은 컴파일러가 오류를보고하게됩니다. 소비자 <integer> myConsumer = (y) -> {system.out.println ( "x =" + x); // system.out.println ( "y =" + y)을 명명합니다. System.out.println ( "this.x =" + this.x); System.out.println ( "lambdascopetest.this.x =" + lambdascopetest.this.x); }; myConsumer.accept (x); }} public static void main (String ... args) {lambdascopetest st = new lambdascopetest (); lambdascopetest.firstlevel fl = St.New firstLevel (); fl.methodinfirstlevel (23); }}이 코드는 다음을 출력합니다.
x = 23y = 23this.x = 1lambdascopetest.this.x = 0
예제의 Lambda Expression MyConsumer의 매개 변수 Y를 X로 바꾸면 컴파일러가 오류를보고합니다.
소비자 <integer> myConsumer = (x) -> {// ....};컴파일러 오류 메시지는 다음과 같습니다. "변수 x는 메소드 메소드에서 이미 정의되어 있습니다. Lambda 표현이 새로운 범위를 도입하지 않기 때문에 오류 가보고됩니다. 따라서 Lambda 표현식에서 외부 클래스의 도메인 필드, 메소드 및 공식 매개 변수에 직접 액세스 할 수 있습니다. 이 예에서, Lambda Expression MyConsumer는 MethodInFirstRevel의 메소드의 매개 변수 X에 직접 액세스합니다. 외부 클래스의 구성원에게 액세스 할 때이 키워드도 직접 사용됩니다. 이 예에서는 this.x가 FirstLevel.x를 나타냅니다.
그러나 로컬 또는 익명의 클래스와 마찬가지로 Lambda 표현식은 로컬 변수 또는 최종 (또는 최종)로 선언 된 외부 멤버 만 액세스 할 수 있습니다. 예를 들어 샘플 코드 MethodInFirstRevel 메소드에서 "X = 99"전에 주석을 제거합니다.
// 다음 진술은 컴파일러가 오류를보고하게됩니다. 소비자 <integer> myConsumer = (y) -> {system.out.println ( "x =" + x); // system.out.println ( "y =" + y)을 명명합니다. System.out.println ( "this.x =" + this.x); System.out.println ( "lambdascopetest.this.x =" + lambdascopetest.this.x); };이 문서에서 매개 변수 x의 값이 수정되므로 MethodInFirstRevel의 매개 변수 X는 더 이상 최종으로 간주 될 수 없습니다. 따라서 Java 컴파일러는 Lambda 표현식이 로컬 변수 x에 액세스하는 "Lambda 표현식에서 참조 된 로컬 변수"와 같은 오류를보고합니다.
대상 유형
람다 표현의 유형을 결정하는 방법은 무엇입니까? 적절한 연령의 군인을 필터링하기위한 코드를 살펴 보겠습니다.
p-> p.getgender () == person.sex.male && p.getage ()> = 18 && p.getage () <= 25
이 코드는 두 곳에서 사용되었습니다.
Public Static void printpersons (List <person> 명단, 검사원 테스터) - 솔루션 3
Public void printpersonswithpredicate (List <person> 명단, 술어 <사람> 테스터) - 계획 vi
Printpersons 메소드를 호출 할 때이 메소드는 수표 유형 매개 변수를 기대합니다. 이때, 위의 표현식은 검사원 유형 표현식입니다. PrintPersons를 Predice 메소드를 호출 할 때 유형의 술어 <person>의 매개 변수가 예상됩니다. 현재 동일한 표현은 유형의 술어 <person>입니다. 이와 마찬가지로, 방법에 의해 예상되는 유형에 의해 결정된 유형을 대상 유형이라고합니다 (실제로 스칼라의 유형 추론이 여기에서 더 적합하다고 생각합니다). Java 컴파일러는 Lambda 표현을 발견 할 때 대상 유형의 컨텍스트 또는 위치를 통해 Lambda 표현의 유형을 결정합니다. 즉, Lambda 표현식은 Java 컴파일러가 유형을 유추 할 수있는 경우에만 사용할 수 있습니다.
대상 유형 및 메소드 매개 변수
메소드 매개 변수의 경우 Java 컴파일러는 두 가지 언어 기능에 의존하여 대상 유형을 결정해야합니다. 과부하 파싱 및 유형 매개 변수 추론.
다음 두 기능적 인터페이스 (java.lang.runnable 및 java.util.concurrent.callable <v>)를 살펴보십시오.
공개 인터페이스 runnable {void run (); } public interface callable <v> {v call (); }runnable.run () 메소드는 값을 반환하지 않으며 Callable.call () 메소드에는 값이 있습니다.
다음과 같은 호출 메소드를 과부하한다고 가정 해 봅시다.
void invoke (runnable r) {r.run (); } <t> t invoke (callable <t> c) {return c.call (); }다음 진술에서 어떤 방법이 호출 될 것인지.
String s = invoke(() -> "done");
이 메소드에는 리턴 값이 있고 Invoke (runnable <t>)가 값을 반환하지 않기 때문에 호출 (Callable <t>)이 호출됩니다. 이 경우 Lambda 표현식 (() -> "done")의 유형은 <t>라고 부릅니다.
직렬화
Lambda 발현의 목표 유형과 호출되는 매개 변수 유형이 직렬화 가능하면 Lambda 발현도 시리얼링 가능합니다. 그러나 내부 클래스와 마찬가지로 Lambda 표현의 직렬화는 권장되지 않습니다.