[Java] ๋๋ค์์ ์ฌ์ฉํ๋ ์ด์ (lazy evaluation)
ํ๊ทธ: Java
์นดํ ๊ณ ๋ฆฌ: Java
๋๋ค์์ด๋?
ํจ์ํ ์ธํฐํ์ด์ค(์ถ์ ๋ฉ์๋๋ฅผ ํ๊ฐ๋ง ๊ฐ์ง ์ธํฐํ์ด์ค)๋ฅผ ์ด์ฉํด ๊ตฌํ๋ถ๋ฅผ ์ถ์ฝํด ํํํ๋ ๋ฐฉ์์ด๋ค. ์ต๋ช ํด๋์ค๋ฅผ ์ด์ฉํด ๊ตฌํ์ ํ๋ ๋ฐฉ์์ ์ข ๋ ์ค์ฌ์ ํํํ ๊ฒ์ด๋ผ๊ณ ๋ณด๋ฉด๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@FunctionalInterface
interface Calculator {
int compute(int a, int b);
}
...
// ์ต๋ช
ํด๋์ค
Calculator c = new Calculator() {
@Override
public int compute(int a, int b) {
return a + b;
}
};
// ๋๋ค
Calculator cal = (a, b) -> a + b;
cal.compute(1,2); // 3
๋งค๋ฒ 1ํ์ฑ ๊ตฌํ์ ์ํด ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ๋๊ฒ์ด ๊ท์ฐฎ๋ค๋ฉด ์๋์๊ฐ์ java์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํ๋ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค. java ์์๋ ์์ฃผ ๊ตฌํ์ด ๋ ๋งํ ๊ธฐ๋ฅ์ ์ธํฐํ์ด์ค๋ฅผ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ ์ ๊ณตํ๊ณ ์๋ค. ์ธํฐํ์ด์ค ์ด๋ฆ๊ณผ ๋ชจ์์ ๋ณด๋ฉด ์ด๋ค ์ญํ ์ ํ๋์ง ๋ช ํํ ์ ์ ์๋ค. ์ด ๋ฐ์๋ ๋ค์ํ ์ธํฐํ์ด์ค๋ฅผ ์ง์ํ๋ค.
Funtional Interface | Description | Method |
---|---|---|
Predicate | T -> boolean |
boolean test(T t) |
Consumer | T -> void |
void accept(T t) |
Supplier | () -> T |
T get() |
Function<T,R> | T -> R |
R apply(T t) |
Comparator | (T, T) -> int |
int compare(T a, T b) |
Runnable | () -> void |
void run() |
Callable | () -> T |
V call() |
์๋ฅผ ๋ค์ด java ์์ ์ ๊ณตํ๋ ์ธํฐํ์ด์ค๋ฅผ ์ด์ฉํ๋ฉด ์๋์ ๊ฐ์ด ๋ฏธ๋ฆฌ ์ ํด์ง ์ธํฐํ์ด์ค ํ์ ์ผ๋ก ๋ฐ์ ์ ์๋ค.
1
2
3
// java.util.Comparator ์ฌ์ฉ
Comparator<Integer> co = (a, b) -> a + b;
System.out.println(co.compare(100, 2)); // 102
๋๋ค์์ ์ฌ์ฉ ๋ชฉ์
๋๋ค๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐ๋ก ํด๋์ค๋ฅผ ๋ง๋ค๊ฑฐ๋ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ์ง ์์๋ ๋๋ค.(java์์ ๊ธฐ๋ณธ ์ง์ํ๋ ํจ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ) ์ฝ๋์ ์์ ์ค์ผ ์ ์๋ค.
๋๋ค์ ์ฌ์ฉ ๋ชฉ์ ์ ํจ์๋ฅผ ์ผ๊ธ ๊ฐ์ฒด
๋ก ๋ค๋ฃจ๊ฒ ๋ค๋ ๊ฒ์ ์๋ค.
์ผ๊ธ ๊ฐ์ฒด๋ ๋ค๋ฅธ ํจ์์ ์ธ์๋ก ์ ๋ฌ๊ฐ๋ฅ ํ๊ณ , ํจ์์์ ๋ฐํ๊ฐ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ ํจ์๋ฅผ ๋งํ๋ค. (javaScript ์ function
์ฒ๋ผ)
ํจ์๋, ์(expression)์ ํตํด ๊ฐ์ ๋ฐํํ๋ ์ญํ ์ ํ๋ค. ์ด๋ฐ ์ ์์ฒด๋ฅผ ๋ฉ์๋์ ์ธ์๋ก ๋๊ฒจ ์์ ํต๊ณผ ์ฌ๋ถ๋ฅผ ํ๊ฐํ๊ฒ ๋๋ค.
๋๋ค์์ ํตํด ๋ค๋ฅธ ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ๋ก ๊ฐ๋จํ๊ฒ ์ ๋ฌ์ด ๊ฐ๋ฅํด์ง๋ฉด์ ๋ฉ์๋์ ์์๋ถํฐ ๋๊น์ง ๋ฐ์ดํฐ๊ฐ ํ๋ฌ๊ฐ๋ ๊ฒ์ฒ๋ผ ์ฒ๋ฆฌ๋ ์ ์๋ค.
java ์์๋ ๋๋ค์ ๋ฉ์๋ ์ฒด์ด๋(Method Chaining)์ ์ ํ์ฉํ ์ ์๋ Stream
API ๋ฅผ ์ง์ํ๋ค. ์คํธ๋ฆผ์ ์ด์ฉํด ๋ฐ์ดํฐ์ ํํฐ, ๋งคํ, ์ง๊ณ ๋ฑ์ ์์
์ ์ง๊ด์ ์ด๊ณ ์ผ๊ด์ ์ผ๋ก ์ํ ๊ฐ๋ฅํ๋ค.
Stream
์ ๋๋ค์์ ํตํด ์ง์ฐํ๊ฐ(lazy evaluation)
์ ๋ต์ ์ทจํ๊ณ , ๋จ์ถํ๊ฐ(short-circuit evaluation)๋ฅผ ์งํํ๋ค.
๋๋ค ํ์ฉ
Lazy evaluation(์ง์ฐํ๊ฐ)
์ง์ฐ ํ๊ฐ๋ ๋ถํ์ํ ์ฐ์ฐ์ ํผํ๊ธฐ ์ํด ์ฐ์ฐ์ ์ง์ฐ์ํค๋ ๊ฒ์ ๋งํ๋ค. ์๋ ์์์ฝ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ดํด๋ณด์.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class LazyEvaluationExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(4, 15, 20, 7, 3, 13, 2, 20);
List<Integer> chosen = numbers.stream()
.filter(e -> {
System.out.println("e < 10");
return e < 10;
})
.limit(3)
.toList();
chosen.forEach(System.out::println);
}
}
๊ฒฐ๊ณผ
1
2
3
4
5
6
7
8
e < 10
e < 10
e < 10
e < 10
e < 10
4
7
3
๋ง์ฝ ์ ์ฐ์ฐ์ด Eager Evaluation ๋ฐฉ์์ผ๋ก ๋์ํ๋ค๋ฉด 8๊ฐ ํญ๋ชฉ ๋ชจ๋ filter
์ฐ์ฐ์ ํ๊ฒ ๋๋ค.
eager evaluation
๊ทธ๋ฌ๋ ์ค์ ๊ฒฐ๊ณผ์ ์ฐํ ๋ด์ฉ์ ๋ณด๋ฉด filter
ํจ์์ ์คํ์ 5๋ฒ๋ง์ ๋๋๊ณ ์ต์ข
์ง๊ณ ์ฒ๋ฆฌ ํ๋ค.
8๋ฒ ์ฐ์ฐํด์ผ ๋๋ ์์
์ 5๋ฒ๋ง์ ๋๋์ผ๋ฏ๋ก 37.5% ์ ์ฑ๋ฅ ํฅ์์ด ๋ ๊ฒ์ด๋ค. (3/8*100)
๊ฒฐ๊ณผ๊ฐ ๊ฒฐ์ ๋์๋ง์ ํ๊ฐ๊ฐ ์ค์ง๋๋ค. (Short-circuiting)
lazy evaluation
๋ค๋ฅธ ์์๋ ์ดํด๋ณด์.
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
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.function.Supplier;
public class DelayedEvaluationExample {
public static void main(String[] args) {
System.out.println("------ lazy evaluation ------");
long start1 = System.currentTimeMillis();
getLazyValue(true, DelayedEvaluationExample::computeValue);
getLazyValue(false, DelayedEvaluationExample::computeValue);
getLazyValue(false, DelayedEvaluationExample::computeValue);
System.out.println("Time: " + (System.currentTimeMillis() - start1)/1000);
System.out.println();
System.out.println("------ eager evaluation ------");
long start2 = System.currentTimeMillis();
getEagerValue(true, computeValue());
getEagerValue(false, computeValue());
getEagerValue(false, computeValue());
System.out.println("Time: " + (System.currentTimeMillis() - start2)/1000);
}
private static int computeValue() {
System.out.println("Computing the value...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 42;
}
public static void getLazyValue(boolean valid, Supplier<Integer> supplier) {
if (valid) {
System.out.println("Value: " + supplier.get());
} else {
System.out.println("Invalid");
}
}
public static void getEagerValue(boolean valid, int value) {
if (valid) {
System.out.println("Value: " + value);
} else {
System.out.println("Invalid");
}
}
}
๊ฒฐ๊ณผ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
------ lazy evaluation ------
Computing the value...
Value: 42
Invalid
Invalid
Time: 1
------ eager evaluation ------
Computing the value...
Value: 42
Computing the value...
Invalid
Computing the value...
Invalid
Time: 3
์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด, eager evaluation ์ ํธ์ถ์ ํ๋ ๊ทธ ์ฆ์ ์คํ๋๋ค. ๋ฐ๋ฉด์ lazy evaluation ์ ์(expression)์ ๋ํ ํ๊ฐ๊ฐ ์ค์ ์ด๋ฃจ์ด์ง๋ ์์ ์ ์คํ๋๋ค. ์ฆ, ํธ์ถ์ ์ต๋ํ ๋ค๋ก ๋ฆ์ถ๋ค.
switch ๋ฌธ์ ๋จ์ํ ํ ์ ์๋ค.
์๋ฅผ ๋ค์ด ์์ผ ๋ณ ํ ์ผ์ ์ถ๋ ฅํ๋ ํ๋ก๊ทธ๋จ์ ์์ฑํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
1
2
3
4
5
6
7
8
9
public enum Week {
SATURDAY,
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY
}
๊ฐ ์์ผ์ ๋ํ enum
์ ์ ์ํ๊ณ ์์ผ๊ณผ ๋งคํ๋๋ ๋ฉ์๋๋ฅผ ์ ์ํ๋ค.
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
public class GoalPrinter {
public void saturdayGoal() {
System.out.println("Saturday: Relax and recharge for the upcoming week.");
}
public void sundayGoal() {
System.out.println("Sunday: Set clear goals for the week ahead.");
}
public void mondayGoal() {
System.out.println("Monday: Focus on improving a specific skill.");
}
public void tuesdayGoal() {
System.out.println("Tuesday: Focus on improving a specific skill.");
}
public void wednesdayGoal() {
System.out.println("Wednesday: Review progress and adjust your plans if needed.");
}
public void thursdayGoal() {
System.out.println("Thursday: Wrap up tasks and prepare for the weekend.");
}
public void fridayGoal() {
System.out.println("Friday: Work on a personal project.");
}
}
ํด๋ผ์ด์ธํธ ์ฝ๋์์ ๊ฐ ์์ผ์ ๋ง๋ ๋ฉ์๋๋ก ๋ถ๊ธฐ์ฒ๋ฆฌํ๋ค.
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
public class ClientApp {
public static void main(String[] args) {
Week week = Week.SATURDAY;
GoalPrinter goalPrinter = new GoalPrinter();
showWeekGoal(goalPrinter, week);
}
private static void showWeekGoal(GoalPrinter goalPrinter,Week week) {
switch (week){
case SATURDAY:
goalPrinter.saturdayGoal();
break;
case SUNDAY:
goalPrinter.sundayGoal();
break;
case MONDAY:
goalPrinter.mondayGoal();
break;
case TUESDAY:
goalPrinter.tuesdayGoal();
break;
case WEDNESDAY:
goalPrinter.wednesdayGoal();
break;
case THURSDAY:
goalPrinter.thursdayGoal();
break;
case FRIDAY:
goalPrinter.fridayGoal();
break;
}
}
}
์ ์์ค์ฝ๋๋ ์์ผ์ enum
์ผ๋ก ์ ์ํ๊ณ , switch ๋ฌธ์ ํตํด ์์ผ์ ํด๋นํ๋ ํจ์๋ฅผ ์คํํ๊ณ ์๋ค.
๊ทธ๋ฌ๋ enum
์ ์์ผ์ด ์ถ๊ฐ๋๋ฉด, GoalPrinter
ํจ์๋ ๋ฐ๊ฟ์ผํ๊ณ switch ๋ฌธ์ ์ผ์ด์ค๋ ์ถ๊ฐํด์ผ ํ๋ค.
์ด ์ค ์ด๋ํ๋๋ผ๋ ์ค์๋ก ๊ฑด๋๋ฐ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ ๊ฒ์ด๋ค. ์ด๋ฐ ๋ฐฉ์์ SOLID ํจํด์ OCP(Open-Closed Principle)๋ฅผ ์๋ฐํ๊ฒ ๋๋ค.
๋๋ค๋ฅผ ์ด์ฉํด switch ์ ๊ฑฐํ๊ธฐ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public enum Week {
SATURDAY(GoalPrinter::saturdayGoal),
SUNDAY(GoalPrinter::sundayGoal),
MONDAY(GoalPrinter::mondayGoal),
TUESDAY(GoalPrinter::tuesdayGoal),
WEDNESDAY(GoalPrinter::wednesdayGoal),
THURSDAY(GoalPrinter::thursdayGoal),
FRIDAY(GoalPrinter::fridayGoal);
public final Consumer<GoalPrinter> consumer;
Week(Consumer<GoalPrinter> consumer) {
this.consumer = consumer;
}
}
switch ์์ enum ํ์
์ ๋ฐ๋ฅธ ๋ฉ์๋๋ก ๋ถ๊ธฐ์ฒ๋ฆฌ ํ์ง ์๊ณ , enum
์์ ๋ฐ๋ก ์ถ์๋ฉ์๋๋ฅผ ๊ตฌํํด enum ํ์
์ ์ฐ๊ฒฐ์ํจ๋ค. ํด๋น ์์ ์์๋ ๋ฏธ๋ฆฌ ๊ตฌํ๋ ๋ฉ์๋๋ฅผ ์ฐธ์กฐ(method reference)ํ๋ ๋ฐฉ์์ผ๋ก ์ ์ํ๋ค.
์๋ก ์ธํฐํ์ด์ค๋ฅผ ์ ์ํด๋ ๋์ง๋ง java ์์ ์ ๊ณตํ๋ Consumer
์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ค. ํด๋ผ์ด์ธํธ ํธ์ถ์ ์๋์ ๊ฐ์ด ํ๋ค.
1
2
3
4
public static void main(String[] args) {
Week week = Week.FRIDAY;
week.consumer.accept(new GoalPrinter());
}
์ด ๋ฐฉ์์ ์ฅ์ ์ enum
์ ์์๋ฅผ ์ถ๊ฐํ ๋ ๋ฉ์๋ ๊ตฌํ์ ๊ฐ์ ํ ์ ์์ด ์ฝ๋๋ฅผ ๋ถ์ฐ๋์ง ์๊ฒ ๊ด๋ฆฌ ํ ์ ์๊ณ , ํด๋ผ์ด์ธํธ ์ฝ๋๋ฅผ ๋งค๋ฒ ์์ ํ ํ์๋ ์๋ค.
๋ค์ ๊ธ์์๋ Stream ์ ๋ํด ์ข ๋ ์์ธํ ์์๋ณธ๋ค. Stream ์ ์ด๋ค๋ ๊ฒ์ ์๋ฏธ(์ ์ธํ ํ๋ก๊ทธ๋๋ฐ)์ ์คํธ๋ฆผ์ด ์ด๋ค์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋์ง ์์๋ณด๊ณ , ๊ธฐ์กด์ ์ ํต์ ์ for-loop ๋ฐฉ์๊ณผ ๋น๊ต ๋ฐ ์ฃผ์ํด์ผ ํ ์ ์ ์์๋ณธ๋ค.
๋๊ธ๋จ๊ธฐ๊ธฐ