Post

(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.