1. 람다식이란?

  • 함수적 프로그래밍 : 병렬 처리와 이벤트 지향 프로그래밍에 적합함.
    => 객체 지향 프로그래밍과 함수적 프로그래밍을 혼합함으로써 더욱 효율적인 프로그래밍이 될 수 있음.
  • 람다식 : 익명 함수(anonymous function)를 생성하기 위한 식.
  • 자바에서 람다식을 사용할 때의 장점
    1. 자바 코드가 매우 간결해짐.
    2. 컬렉션의 요소를 필터링하거나 매핑해서 원하는 결과를 쉽게 집계할 수 있음.
  • 람다식의 형태는 매개 변수를 가진 코드 블록이지만, 런타임 시에는 익명 구현 객체를 생성함.
  • Runnable 인터페이스 구현 코드
1
2
3
4
5
6
7
// Runnable 인터페이스의 익명 구현 객체를 생성하는 전형적인 코드
Runnable runnable = new Runnable() {
    public void run() {...}
};

// 위 익명 구현 객체를 람다식으로 표현
Runnable runnable = () -> {...};
  • 람다식은 (매개변수)->{실행코드} 형태로 작성되며, 런타임 시에 인터페이스의 익명 구현 객체로 생성됨.

2. 람다식 기본 문법

1) 람다식 작성법

(타입 매개변수, ...) -> { 실행문; ... }

  • (타입 매개변수, ...) : 오른쪽 중괄호 {} 블록을 실행하기 위해 필요한 값을 제공하는 역할.
  • -> : 매개 변수를 이용해서 중괄호 {}를 실행한다는 뜻

2) 예시

a -> System.out.println(a);

  • 매개 변수 타입은 런타임 시에 대입되는 값에 따라 자동으로 인식될 수 있으므로 람다식에서는 매개 변수 타입을 일반적으로 언급하지 않음.
  • 하나의 매개변수만 있다면 괄호 생략 가능.
  • 하나의 실행문만 있다면 중괄호 생략 가능.

2-1) 예시

  • (x, y) -> { return x + y; };
  • (x, y) -> x + y :
    중괄호에 return문만 있을 경우 생략

3. 타겟 타입과 함수적 인터페이스

  • 자바는 메서드를 단독으로 선언할 수 없고 항상 클래스의 구성 멤버로 선언하기 때문에 람다식은 단순히 메서드를 선언하는 것이 아니라 이 메서드를 가지고 있는 ‘객체’를 생성해 냄.
  • 람다식은 인터페이스의 익명 구현 객체를 생성함.
    => 인터페이스는 직접 객체화할 수 없기 때문에 구현 클래스가 필요한데, 람다식은 익명 구현 클래스를 생성하고 객체화함.
  • 람다식은 대입될 인터페이스의 종류에 따라 작성 방법이 달라지기 때문에 람다식이 대입될 인터페이스를 람다식의 타겟 타입(target type)이라고 함.

4. 함수적 인터페이스(@FunctionalInterface)

  • 람다식이 하나의 메서드를 정의하기 때문에 두 개 이상의 추상 메서드가 선언된 인터페이스는 람다식을 이용해서 구현 객체를 생성할 수 없음.
  • 함수적 인터페이스(functional interface) : 하나의 추상 메서드가 선언된 인터페이스
  • @FunctionalInterface
    함수적 인터페이스를 작성할 때 두 개 이상의 추상 메서드가 선언되지 않도록 컴파일러가 체크해주는 기능.
    => 두 개 이상의 추상 메서드가 선언되면 컴파일 오류 발생시킴.

5-1. 매개변수와 리턴값이 없는 람다식

1
2
3
4
5
6
7
@FunctionalInterface
public interface MyFunctionalInterface {
	
	// 람다식 MyFunctionalInterface fi = () -> {...}
	// 해당 람다식에서 매개변수가 없는 이유는 method()가 매개변수를 가지지 않기 때문.
	public void method();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyFunctionalInterfaceExample {
	
	public static void main(String[] args) {
		
		MyFunctionalInterface fi;
		
		fi = () -> {
			String str = "method call1";
			System.out.println(str);
		};
		// 람다식이 대입된 인터페이스의 참조 변수는 method()를 호출할 수 있음.
		// method() 호출은 람다식의 중괄호{}를 실행시킴.
		fi.method();
		
		fi = () -> { System.out.println("method call2"); };
		fi.method();
		
		fi = () -> System.out.println("method call3");
		fi.method();
		
	}

}

5-2. 매개변수가 있는 람다식

1
2
3
4
5
6
7
@FunctionalInterface
public interface MyFunctionalInterface2 {
	
	// 람다식 MyFunctionalInterface2 fi = x -> {...}
	public void method(int x);
	
}
1
2
3
4
5
6
7
8
9
10
11
12
public class MyFunctionalInterfaceExample2 {
	
	public static void main(String[] args) {
		
		MyFunctionalInterface2 fi;
		
		fi = x -> System.out.println(x*5);
		fi.method(2);	// 매개값으로 2를 줬으므로 위 람다식의 x 변수에 2가 대입됨 | 결과: 10
		
	}

}

5-3. 리턴값이 있는 람다식

1
2
3
4
5
6
7
@FunctionalInterface
public interface MyFunctionalInterface3 {
	
	// 람다식 MyFunctionalInterface3 fi = (x,y) -> { ...; return값; }
	public int method(int x, int y);
    
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyFunctionalInterfaceExample3 {
	
	public static void main(String[] args) {
		
		MyFunctionalInterface3 fi;
		
		fi = (x, y) -> x + y;
		System.out.println(fi.method(2, 5));
		
		fi = (x, y) -> sum(x, y);
		System.out.println(fi.method(2, 5));
		
	}

	public static int sum(int x, int y) {
		return (x+y);
	}

}