이제 람다식을 정리해보자. 앞서 로컬클래스와 이름 없이 사용하는 로컬클래스인 익명 객체에 대해 알아보았다.
그리고 이 람다식은 런타임시 익명객체를 생성해주는 함수 생성 식이다. 이를 사용하면 자바 코드가 매우 간결해주고 컬렉션의 요소를 필터링하거나 매핑해서 원하는 결과를 쉽게 집계할 수 있다.
람다식은 아래와 같이 인터페이스 변수 = 람다식의 형태로 작성된다.
Runnable runnable = () -> {};
이렇게 보면 자바의 메소드를 선언하는 것 처럼 보이지만, 자바는 메소드만을 단독으로 생성할 수 없고, 항상 클래스의 구성 멤버로 선언하기 때문에 자바는 이 메소드를 가지는 객체를 생성하고 인터페이스 변수에 대입된다. 위 코드는 Runnable 변수에 대입되므로 람다식은 Runnable 익명 구현 개체를 생성 후 대입해 주는 것이다.
Runnable runnable = new Runnable(){
};
이런식으로!
이렇듯 람다식은 대입될 인터페이스 종류에 따라 작성 방법이 달라지기에 람다식이 대입될 인터페이스를 람다식의 타겟 타입이라고 한다.
그렇다면 타겟타입에 따라 람다식이 어떻게 사용되는지 알아보자
타겟 타입과 함수적 인터페이스
I. 함수적 인터페이스(@FunctionalInterface)
람다식을 사용하기 위해서는 타켓타입 인터페이스는 하나의 추상 메소드만 선언이 되어있어야 한다. 그리고 이러한 인터페이스를 함수적 인터페이스라고 한다. 인터페이스 선언 시 @FunctionalInterface 애노테이션을 붙여주면 두개 이상의 추상 메소드가 생성되지 않도록 컴파일러가 자동으로 체킹을 해준다.
II. 매개변수와 리턴값이 없는 람다식
// # 1. functionalInterface 선언
@FunctionalInterface
public interface Vehicle {
public void run();
}
// # 2. Main 에서 해당 인터페이스 구현 방식
public class Main {
public static void main (String args[]){
Vehicle vi; // # 2.1 인터페이스 선언
vi= () -> {
// # 2.2 추상메소드 run에 대한 구현을 해준다.
System.out.println("the Car is running");
} ;
vi.run();// # 2.3 메소드 실행
}
}
III. 매개변수와 리턴값이 있는 경우
public class Main {
public static void main (String args[]){
Vehicle vi;
vi= () -> {
System.out.println("the Car is running");
} ;
vi.run();
}
}
람다식의 클래스 멤버와 로컬 변수 사용
람다식의 실행블록에서는 클래스 멤버인 필드와 메소드를 제약 없이 사용할 수 있지만 this를 사용할 땐 조심해야 한다. 람다 내부에서 사용되는 this 는 내부적으로 생성되는 익명객체의 참조가 아니라 람다식을 실행한 객체의 참조이다.
// #1. Main 에서 객체 호출
public class Main {
public static void main (String args[]){
UsingThis usingThis = new UsingThis();
UsingThis.Inner inner = usingThis.new Inner();
// # 1.1 usingThis 인스턴스의 내부 클래스를 호출하는 방식
inner.method();
}
}
// 2. UsingThis 객체
public class UsingThis {
public int field=10;
class Inner {
int field = 20;
void method(){
MyFunctionalInterface fi = () -> {
int field = 30;
System.out.println("field : " + field); // 30
System.out.println("this.field : " + this.field); //20
System.out.println("UsingThis.this.field : " + UsingThis.this.field); // 10
};
fi.method();
}
}
}
UsingThis 객체를 살펴보면 field 라는 변수가 아래와 같이 세개 선언되어 있다.
- 바깥클래스의 필드 변수 // int 10
- 중첩클래스의 필드 변수 // int 20
- 람다식 내부의 로컬 변수 // int 30
위에서 말했듯, 람다식에서의 this는 자기 자신이 아니라 자신을 호출한 객체를 참조한다. this.field를 호출 했을 때 중첩클래스의 필드 변수인 20이 찍힌걸 확인할 수 있었다. Usingthis.this.field를 호출하면 바깥 클래스를 참조한다.
로컬변수는 익명객체, 로컬클래스와 동일하게 final의 특성을 갖는다. 따라서 매개변수 또는 로컬변수를 람다식에서 읽는 것은 허용이 되지만 람다식 내부 또는 외부에서 변경할 수 없다.
'Study > Java' 카테고리의 다른 글
자바 기본서를 다시 읽다. 5 - 함수적 인터페이스의 Default Method (0) | 2022.03.27 |
---|---|
자바 기본서를 다시 읽다. 4 - 표준 API의 함수적 인터페이스 (0) | 2022.03.16 |
자바 기본서를 다시 읽다. 3 - 로컬클래스와 익명객체, 그리고 람다식 (1) (0) | 2022.03.15 |
자바 기본서를 다시 읽다. 2 - 인터페이스 (0) | 2022.03.11 |
자바 기본서를 다시 읽다. 1-JVM의 메모리 사용 영역 (0) | 2022.03.10 |