(Java) lambda 기본 개념
Lambda
1
2
3
4
5
6
7
8
9
10
// 기본 형식. 2줄 이상일 때
( parameters ) -> { expression body }
// 별다른 내용 없이 바로 return할 수 있는 경우
( parameters ) -> expression
Lambda를 활용한 Thread
보통 자바에서 Thread는 다음과 같이 Thread로 사용할 class에 Runnable interface를 implements하여 Thread객체에 파라미터로 전달하여 사용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class
TestThread
implements
Runnable
{
@
Override
public
void
run
()
{
System
.
out
.
println
(
"newTHread"
);
}
}
1
2
3
Thread t = new Thread(new TestThread());
t.start();
그러나 Runnable interface를 무명 클래스로 바로 구현해서 사용하는 경우도 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
new
Thread
(
new
Runnable
() {
@Override
public void
run
() {
System
.
out
.
println
(
"inner"
)
;
}
})
.
start
()
;
Runnable interface는 함수형 인터페이스이기 때문에 이 경우 람다식을 사용할 수 있다.
1
2
3
4
new Thread(()->{
System.out.println("lambda");
}).start();
이같은 방법을 이벤트 핸들러 등 코드가 지저분해지는 구간에 적용하면 말끔하게 처리 가능하다.
Functional Interface
new Runnable()...
을 람다로 대체 할 수 있었던 것은, Runnable이 함수형 인터페이스 이기 때문이다.- 함수형 인터페이스는바디가 없는 메서드(추상 메서드)를 하나만 가지고 있는 인터페이스 를 말한다.
- 인터페이스이므로 new를 통해 추상 메서드를 구현해준다면 익명 객체로 만들 수 있다.
- default method는 바디가 있기 때문에 추상 메서드가 아니므로 여러 개 가질 수 있다.
- 함수형 인터페이스는바디가 없는 메서드(추상 메서드)를 하나만 가지고 있는 인터페이스 를 말한다.
- 람다를 넘기는게 함수가 넘어가는 것 처럼 보이지만 사실은 파라미터 타입에 알맞은 익명 객체를 만들고, 람다 함수를 이 익명 객체의 추상 메서드 바디에 할당하여 넘기는 것이다.
- 자바에서 함수는 일급 시민이 아니기 때문에, 어쨌든 넘어가는건 객체다.
- 이 익명 객체의 원형이 되는 클래스는 반드시 추상 메서드를 하나만 가지고 있어야 한다. 즉,함수형 인터페이스 여야 한다.
- 이는 객체를 만들면서 람다 함수를 추상 메서드 바디에 할당해야 하는데 추상 메서드가 여러 개 있으면 람다를 어떤 메서드에 대응시켜야 할지 알 수 없기 때문이다.
- 람다 함수가 추상 메서드 바디에 할당된다는건, 평소 익명 객체를 바로 구현해서 사용할 때 생각해보면 된다. 거기서 필요없는거 다 빼고 메서드 파라미터와 바디만 남겨놓은게 람다다.
- 결국 함수를 담은 객체가 넘어가는 것이기 때문에, 함수형 인터페이스 변수에 함수를 담아 넘기거나 리턴할 수 있다.
@FunctionalInterface
annotation- 붙이면 추상 메소드가 두 개 이상일 때 컴파일 오류로 알려준다.
- 함수형 인터페이스 임을 명시하는 효과도 있으므로 사용하면 좋다.
- StreamAPI의 filter나 map에 넘어오는 람다는 Predicate, Function 이라는 표준 함수형 인터페이스다.
직접 정의하는 경우?
1
2
3
4
5
@FunctionalInterface
interface VItoI{
public int out(int... a);
}
1
2
3
4
5
VItoI add = (int... a) -> {return a[0] + a[1];};
VItoI mul = (int... a) -> a[0] \* a[1];
System.out.println(add.out(1, 3));
System.out.println(mul.out(1, 2));
add, mul은 interface 객체이기 때문에 그 내부에 구현한 method “out”을 호출해줘야 한다.
메서드 참조 (Method References)
람다를 메서드 참조로 대신할 수 있음. BigInteger::nextProbablePrime
This post is licensed under CC BY 4.0 by the author.