Publish:

ํƒœ๊ทธ:

์นดํ…Œ๊ณ ๋ฆฌ:

๋žŒ๋‹ค์‹์ด๋ž€?

ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค(์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ํ•œ๊ฐœ๋งŒ ๊ฐ€์ง„ ์ธํ„ฐํŽ˜์ด์Šค)๋ฅผ ์ด์šฉํ•ด ๊ตฌํ˜„๋ถ€๋ฅผ ์ถ•์•ฝํ•ด ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ต๋ช…ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•ด ๊ตฌํ˜„์„ ํ•˜๋Š” ๋ฐฉ์‹์„ ์ข€ ๋” ์ค„์—ฌ์„œ ํ‘œํ˜„ํ•œ ๊ฒƒ์ด๋ผ๊ณ  ๋ณด๋ฉด๋œ๋‹ค.

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 ๋ฐฉ์‹๊ณผ ๋น„๊ต ๋ฐ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์„ ์•Œ์•„๋ณธ๋‹ค.

reference

๋ฐฉ๋ฌธํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๋Œ“๊ธ€,์ง€์ ,ํ”ผ๋“œ๋ฐฑ ์–ธ์ œ๋‚˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜Š

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ