람다식이란?
람다식은 자바8에서 함수형 프로그래밍을 도입하면서 지원되기 시작한 문법이다. 기본적으로 람다식은 익명 구현객체를 만드는 새로운 방식이다.
기존의 방식대로 Runnable 인터페이스의 익명 구현 객체를 생성하는 코드는 다음과 같다.
Runnable runnable = new Runnable(){
public void run(){
...
}
}
람다식을 이용하면 아래처럼 더 짧고 간결하게 나타낼 수 있다.
Runnable runnable = () -> {
...
}
람다식은 런타임 시에 어떤 인터페이스를 구현하는 것인지 결정된다. 즉, 람다식이 대입되는 타입이 무었인지에 따라 구현되는 인터페이스가 결정된다. 위 코드는 Runnable 에 대입되므로 람다식은 런타임에 Runnable의 익명 구현 객체를 생성한다.
람다식으로 구현할 수 있는 인터페이스는 "추상 메서드가 한개인 인터페이스"만 가능하다. 이런 인터페이스를 함수적인터페이스 라고 한다.
람다식 문법
람다식의 기본 문법은 아래와 같다.
(타입 매개변수, ...) ->{실행문}
매개변수의 타입은 보통 생략한다.(런타임에서 강력한 타입 추론기능으로 타입을 추측하기 대문이다. 정상동작하지 않으면 그때 타입을 적어준다.)
만약, 매개변수가 하나라면, () 를 생략할 수 있고, 실행문이 하나라면 {} 를 생략할 수 있다.
a -> System.out.println(a);
단, 매개변수가 하나도 없는 경우에는 빈 괄호()를 사용해야만 한다.
() -> {실행문; ...}
결과값을 리턴해야 한다면 return 키워드를 사용하면 된다.
(x, y) -> { return x + y;}
{} 에 return 문만 있으면 return 키워드를 생략할 수 있다. 보통 생략하여 쓴다고 한다.
(x, y) -> { x + y;}
타겟 타입과 함수적 인터페이스
위에서 말했듯이, 람다식은 추상 메서드가 한개인 인터페이스의 익명구현 객체를 만드는 방법이다. 또한 그 타입은 런타임에 어떤 타입의 변수에 대입되는지에 따라 결정된다고 했다. 이 타입을 타겟 타입이라 한다.
따라서, 익명 구현 객체를 만들고자 하는 타겟 타입인 인터페이스의 추상메서드의 반환값 여부와 매개변수 수에 따라 람다식의 형태를 다르게 작성해야 한다. 앞의 예시에서 Runnable 인터페이스의 run 메서드는 반환이 없고, 매개변수도 없으므로 람다식도 그렇게 작성한 것이다.
람다식이 대입된 변수는 일반적인 방법과 동일한 방법으로 람다식의 {} 내부의 코드를 실행할 수 있다.
@FunctionalInterface // 이 애모테이션이 붙어있으면 인터페이스의 추상메서드는 하남나 있어야 한다.
public interface MyFInterface{
public void method();
}
MyFinterface fi = () -> {System.out.println("Hello World");}
fi.method(); // 람다식이 실행되어 System.out.println("Hello World");이 실행된다.
람다식에서 클래스의 멤버 사용과 로컬 변수 사용.
람다식 내부에서 람다식을 작성하는 클래스의 멤버를 자유롭게 사용할 수 있다. 즉, 다음과 같은 코드는 가능하다.
@FunctionalInterface // 이 애모테이션이 붙어있으면 인터페이스의 추상메서드는 하남나 있어야 한다.
public interface MyFInterface{
public void method();
}
public class Main{
private int field1= 10;
private void method1(){
System.out.println("method1() 호출");
}
public void method2(){
MyFInterface fi = () ->{
System.out.println(field1);
method1();
}
fi.method();
/*
10
method1() 호출
*/
}
}
단, 이 때 람다식 내부에서 this 키워드를 사용하면 익명구현객체가 아니라, 람다식이 작성되고 있는 객체, 위 코드에선 Main 객체를 의미한다.
위 코드에서 처럼, 람다식은 거의 대부분 어떤 메서드 내부에서 작성된다. 즉, 메서드 내부의 로컬변수를 람다식 내부에서 사용하는 상황이 생긴다. 일반적인 익명 구현객체의 경우와 마찬가지로, 람다식에서는 로컬변수를 읽을 수만 있다.
로컬 변수에 다른 값을 대입하는 행위는 불가능하다. 물론, 로컬변수의 메서드를 호출하는 것은 가능하다.
표준 함수형 인터페이스
자바에서 기본적으로 제공하는 함수형 인터페이스들이 있다. 바로 Consumer, Supplier, Function. Operator, Predicate 인터페이스 들이다. 이들은 다른 클래스의 메서드에서 매개타입으로 사용되어, 람다식을 메서드의 매개변수로 사용할 수 있게 해준다. 각각의 인터페이스들은 각각 다음과같은 일을 하는 람다식으로 사용해야 한다.(이론상으론 문법만 맞으면 다른 용도로 사용할 수 있지만, 전혀 권장하지 않는다)
인터페이스 종류 / 추상 메서드 이름 | 추상 메서드의 특징 |
Consumer / accept() | 매개변수는 있고 리턴값은 없음. 즉, 매개변수를 소비하여 어떤 동작을 하게 함. |
Supplier / getXXX() | 매개값은 없고 리턴값은 있음. 즉, 실행 후 어떤 결과를 제공하는 역할을 함. |
Function / applyXXX() | 매개값과 리턴값 둘 다 있음. 매개값을 리턴값으로 변환하는 역할을 함. |
Operator / applyXXX() | 매개값과 리턴값 둘 다 있음. 매개값에 어떤 연산을 하여 동일한 타입으로 반환함. |
Predicate / testXXX() | 매개값이 있고, 리턴값이 boolean임. 즉, 매개값이 어떤 조건을 만족하는지 여부를 반환함. |
다음 포스팅에선, 이들 표준 함수형 인터페이스에서 제공하는 디폴트 메서드와 정적 메서드를 알아볼 것이다.
'Java > 기초문법' 카테고리의 다른 글
[Java 기본 문법] 7. 상속과 다형성 (0) | 2021.08.17 |
---|---|
[Java 기본 문법] 6. 접근제한자와 캡슐화 (0) | 2021.08.16 |
[Java 기본 문법] 5. 객체와 클래스 (0) | 2021.08.14 |
[Java 기본 문법] 4. 참조타입 (0) | 2021.08.14 |
[Java 기본 문법] 3. 제어문 (0) | 2021.08.13 |