Java Lambda (1) ๊ธฐ๋ณธ

๐Ÿ—“ โฐ ์†Œ์š”์‹œ๊ฐ„ 23 ๋ถ„

์ด๋ฒˆ ํฌ์ŠคํŠธ๋ถ€ํ„ฐ Java 8 ์—์„œ ์ƒˆ๋กœ ๋„์ž…๋œ ๋žŒ๋‹ค(Lambda)์™€ Java 9 ์˜ ๋ชจ๋“ˆ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊นŒ์ง€ ์ญ‰ ๋‹ค๋ค„๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์‹ค ๋žŒ๋‹ค๋„ ๋ช‡ ๋ฒˆ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์‰ฝ๊ฒŒ ์ต์ˆ™ํ•ด์งˆ ์ˆ˜ ์žˆ๋Š” ๊ธฐ์ˆ ์ด์ง€๋งŒ, ๋‚ด๋ถ€์ ์ธ ๋™์ž‘ ์›๋ฆฌ๊นŒ์ง€ ์•Œ์•„๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

Lambda

๋žŒ๋‹ค ๋Œ€์ˆ˜๋Š” 1930๋…„๋Œ€ ์•Œ๋ก ์กฐ ์ฒ˜์น˜Alonzo Church๊ฐ€ ์†Œ๊ฐœํ•œ ํ•จ์ˆ˜์˜ ์ˆ˜ํ•™์  ํ‘œ๊ธฐ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋žŒ๋Œ€ ๋Œ€์ˆ˜๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ˆ˜ํ•™์„ ํƒ๊ตฌํ•˜๋Š” ๋ฐฉ์‹์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ ๋ฆฌ์Šคํ”„์—์„œ ๋žŒ๋‹ค ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•œ ์ดํ›„๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ถ„์•ผ์—์„œ๋„ ๋ฐœ์ „ํ•ด์™”์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
# ์ˆ˜ํ•™์—์„œ์˜ ๋žŒ๋‹ค ๋Œ€์ˆ˜ ํ‘œํ˜„์‹
# x ์ธ์ž๋ฅผ ๋ฐ›์•„์„œ ๋”ํ•˜๋Š” ํ•จ์ˆ˜(๋žŒ๋‹ค)
ฮปx.x+1

# Lisp ๋žŒ๋‹ค ํ‘œํ˜„์‹
# x ์ธ์ž๋ฅผ ๋ฐ›์•„์„œ ๋”ํ•˜๋Š” ํ•จ์ˆ˜(๋žŒ๋‹ค)
(lambda (arg) (+ arg 1))

๋žŒ๋‹ค๋Š” ์ต๋ช… ํ•จ์ˆ˜ (์ด๋ฆ„์ด ์—†๊ณ  ๋‚ด์šฉ๋งŒ ์žˆ๋Š” ํ•จ์ˆ˜)์ด๊ณ , ํ•จ์ˆ˜(Funciton)๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฐ„ํŽธํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ๋‹ค๋ฅธ ํ•จ์ˆ˜์— ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ์ „๋‹ฌํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Function

์ž๋ฐ”์˜ ๋žŒ๋‹ค(ํ•จ์ˆ˜)์™€ ์ต๋ช… ํด๋ž˜์Šค์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜์ง€๋งŒ ๊ธฐ์ˆ ์ ์œผ๋กœ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ์ต๋ช… ํด๋ž˜์Šค๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ syntactic sugar ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

  • ์ต๋ช… ํด๋ž˜์Šค๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•˜์ง€๋งŒ, ํ•จ์ˆ˜๋Š” ํ‰๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ์œ„ํ•œ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์€ ์ž๋ฐ” ํž™์˜ Permanent ์˜์—ญ์— ํ•œ ๋ฒˆ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
  • ๊ฐ์ฒด๋Š” ๋ฐ์ดํ„ฐ์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ์—ฐ๊ด€ํ•ด์„œ ๋™์ž‘ํ•˜์ง€๋งŒ, ํ•จ์ˆ˜๋Š” ๋ฐ์ดํ„ฐ์™€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒํƒœ๋ฅผ ๋ณด์กดํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์—ฐ์‚ฐ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ ์šฉํ•ด๋„ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋ฉฑ๋“ฑ์„ฑ).
  • ํด๋ž˜์Šค์˜ ์Šคํƒœํ‹ฑ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ•จ์ˆ˜์˜ ๊ฐœ๋…๊ณผ ๊ฐ€์žฅ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด๋ก  ์ƒ ์ฐจ์ด์ 

์ด anonymousClass ๋ฉ”์†Œ๋“œ๋Š” Condition ์˜ ๊ตฌํ˜„์ฒด๋ฅผ ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ๋ฉฐ waitFor ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ํด๋กœ์ €
void anonymousClass() {
final Server server = new HttpServer();
waitFor(new Condition(){
@Override
public Boolean isSatisfied() {
return !server.isRunning();
}
})
}

// ๋žŒ๋‹ค๋กœ ํ‘œํ˜„
void closure() {
Server server = new HttpServer();
waitFor(() -> !server.isRunning());
}

๋ณ€์ˆ˜ server ๋Š” Condition ํด๋ž˜์Šค์˜ ์ต๋ช… ์ธ์Šคํ„ด์Šค๋กœ ๋ณต์‚ฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์‚ฌ์šฉ๋  ๋•Œ์™€ ๋„˜๊ฒจ์งˆ ๋•Œ์˜ ์‹œ๊ฐ„ ์ฐจ์ด ๋™์•ˆ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด final ๋กœ ์„ ์–ธ๋ฉ๋‹ˆ๋‹ค(์ตœ์‹  ๋ฒ„์ „์—์„œ๋Š” ๊ฐฑ์‹ ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํŒ๋‹จ๋˜๋ฉด final ๋กœ ์ž๋™ ์ฒ˜๋ฆฌ). ๋ฐ˜๋ฉด ๋žŒ๋‹ค์—์„œ๋Š” ์‹คํ–‰ ํ™˜๊ฒฝ์ด๋‚˜ ๋‹ค๋ฅธ ์กฐ๊ฑด๋“ค์ด ๋ณต์‚ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ ์œ  ๋ฌธ๋ฒ• Capture

  • ์ต๋ช…ํ•จ์ˆ˜(์ต๋ช…ํด๋ž˜์Šค์˜ ๋ฉ”์†Œ๋“œ)์—์„œ this ๋Š” ์ต๋ช… ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.
  • ๋žŒ๋‹ค์—์„œ this๋Š” ๊ทธ๊ฒƒ์„ ๋‘˜๋Ÿฌ์‹ผ ๋ฒ”์œ„๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.
1
2
3
4
5
6
7
8
9
10
public class Example {
private String firstName = "Jack";

public void example() {
Function<String, String> addSurname = surname -> {
// this.firstName ๊ณผ ๋™์ผํ•จ
return firstName + " " + surname;
}
}
}

์˜ˆ์ œ์—์„œ this ๋Š” ๋žŒ๋‹ค๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ๋ฒ”์œ„ -> Example ํด๋ž˜์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— Jack ์„ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Example {
private String firstName = "Charlie";

public void anotherExample() {
Function<String, String> addSurname = new Function<String, String>() {
@Override
public String apply(String surname) {
// this.firstName ์€ ์ปดํŒŒ์ผ ์—๋Ÿฌ
return Example.this.firstName + " " + surname;
}
}
}
}

์ต๋ช… ํด๋ž˜์Šค์—์„œ๋Š” this ํ‚ค์›Œ๋“œ๋Š” ์ต๋ช… ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์˜๋ฏธํ•˜๊ธฐ ๋•Œ๋ฌธ์— firstName ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Example.this.firstName ๊ณผ ๊ฐ™์ด ์ ‘๊ทผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์„€๋„์ž‰ Shadowing

์„€๋„์ž‰์€ ์™ธ๋ถ€, ๋‚ด๋ถ€์— ๋™์ผํ•œ ์ด๋ฆ„์˜ ๋ณ€์ˆ˜๊ฐ€ ์กด์žฌํ•  ๋•Œ ๋‚ด๋ถ€ ๋ฒ”์œ„์˜ ๋ณ€์ˆ˜๊ฐ€ ์šฐ์„ ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์™ธ๋ถ€ ๋ฒ”์œ„์˜ ๋ณ€์ˆ˜๊ฐ€ ๋ฎ์–ด์”Œ์›Œ์ง€๋Š” ๊ฒƒ์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€๋ ค์ง„๋‹ค๊ณ  ํ•ด์„œ ์„€๋„์ž‰์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
public class ShadowingExample {
private String firstName = "Charlie";

public void shadowingExample(String firstName) {
Function<String, String> addSurname = surname -> {
// firstName -> ๋งค๊ฐœ๋ณ€์ˆ˜
// this.firstName -> "Charlie"
return this.firstName + " " + surname;
};
}
}

๋žŒ๋‹ค ๋‚ด๋ถ€์—์„œ this ๊ฐ€ ์‚ฌ์šฉ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๊ฒƒ์„ ๋‘˜๋Ÿฌ์‹ธ๊ณ  ์žˆ๋Š” ๋ฒ”์œ„๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. this ์‚ฌ์šฉ ์‹œ์—๋Š” Charlie ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  this ์—†์ด firstName ์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๋ฌธ๋ฒ•

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Arrays.sort() ์™€ ์ต๋ช… ํด๋ž˜์Šค
Arrays.sort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer first, Integer second) {
return first.compareTo(second);
}
});

// Arrays.sort() ์™€ ๋žŒ๋‹ค
Arrays.sort(numbers, (first, second) -> first.compareTo(second));

// ์‚ฌ์‹ค ์ต๋ช… ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ๋‹ค
Comparator<Integer> asc = (first, second) -> first.compareTo(second);
Arrays.sort(numbers, asc);

๋žŒ๋‹ค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๋Š” ์ต๋ช…์˜ ์ฝ”๋“œ ๋ธ”๋ก์ž…๋‹ˆ๋‹ค. ์œ„ ์˜ˆ์ œ์—์„œ ๋ณด๋ฉด ๋žŒ๋‹ค๋ฅผ ์ด์šฉํ•ด ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋žŒ๋‹ค๊ฐ€ Comparator<Integer> ํƒ€์ž…์œผ๋กœ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค. Comparator ๋Š” ํ•˜๋‚˜์˜ ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ดค์„ ๋•Œ ์ด ๋žŒ๋‹ค๊ฐ€ ๊ทธ ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ ๋‚ด์šฉ์ด๋ผ๊ณ  ๋ณด๊ณ  Comparator<Integer> ํƒ€์ž…์œผ๋กœ ์ฒ˜๋ฆฌํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์–ธ์ œ๋“ ์ง€ ํ•˜๋‚˜๋งŒ ์žˆ๋Š” ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋Š” ๋žŒ๋‹ค๋กœ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
interface Example {
R apply(A arg);
}

// ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐฉ์‹
new Example() {
@Override
public R apply(A args) {
// body
}
}

์ด๋ฅผ ๋žŒ๋‹ค๋กœ ๋ฐ”๊พธ๋Š” ๋ฐฉ๋ฒ•์€ ์ธ์ž ๋ชฉ๋ก๊ณผ ํ•จ์ˆ˜ ๋‚ด์šฉ(body)๋งŒ ๋‚จ๊ธฐ๊ณ  ํ™”์‚ดํ‘œ ๋ถ€ํ˜ธ(->)๋กœ ์—ฐ๊ฒฐํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

1
2
3
(args) -> {
// body
}

Arrays.sort() ์˜ˆ์ œ๋ฅผ ํ•œ ๋ฒˆ ๋” ์‚ดํŽด๋ด…์‹œ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Arrays.sort() ์™€ ์ต๋ช… ํด๋ž˜์Šค
Arrays.sort(numbers, new Comparator<Integer>() {
@Override
public int compare(Integer first, Integer second) {
return first.compareTo(second);
}
});

// ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ๊ณผ ๋ฉ”์†Œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ๊ฐ„๋žตํ™”
Arrays.sort(numbers, (Integer first, Integer second) {
return first.compareTo(second);
});

// ์ธ์ž์˜ ํƒ€์ž…์„ ์ƒ๋žตํ•˜๊ณ  ์ค‘๊ด„ํ˜ธ๋ฅผ ์‚ญ์ œํ•ด ๊ฐ„๋žตํ™”
Arrays.sort(numbers, (first, second) -> first.compareTo(second));

๋งˆ์ง€๋ง‰์— ๊ฐ„๋žตํ™”๋œ ๋ชจ์Šต์„ ๋ณด๋ฉด return ํ‚ค์›Œ๋“œ๋„ ์ƒ๋žต๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ถฉ๋ถ„ํžˆ ์•Œ์•„์ฐจ๋ฆด ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค์— ๋”ฐ๋ผ์„œ int ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š”๋ฐ first.compareTo() ์˜ ๊ฐ’์ด int ์ด๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ถ”๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

ํ•จ์ˆ˜์˜ ์ธ์ž๊ฐ€ ํ•˜๋‚˜๋ผ๋ฉด ์ธ์ž๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ๊ด„ํ˜ธ๋„ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
// x ๋ฅผ ๋ฐ›์•„์„œ x + 1 ์„ ๋ฆฌํ„ดํ•˜๋Š” ๋žŒ๋‹ค
(x) -> x + 1

// ์ธ์ž ๊ด„ํ˜ธ ์ƒ๋žต
x -> x + 1

๋ฌธ๋ฒ• ์š”์•ฝ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ์ธ์ž -> ๋ฐ”๋””
(int x, int y) -> { return x + y; }

// ์ธ์ž ํƒ€์ž… ์ƒ๋žต - ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ถ”๋ก 
(x, y) -> { return x + y; }

// return ๋ฐ ์ค‘๊ด„ํ˜ธ ์ƒ๋žต
(x, y) -> x + y

// ์ธ์ž๊ฐ€ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ ์ธ์ž ๊ด„ํ˜ธ ์ƒ๋žต
x-> x * 2

// ์ธ์ž๊ฐ€ ์—†์œผ๋ฉด ๋นˆ ๊ด„ํ˜ธ๋กœ ํ‘œ์‹œ
() -> System.out.println("Hey there!")

// ๋ฉ”์†Œ๋“œ ์ฐธ์กฐ Method reference
// (value -> System.out.println(value)) ์˜ ์ถ•์•ฝํ˜•
System.out::println

์ฐธ๊ณ