Bibi's DevLog πŸ€“πŸŽ

[Java] λžŒλ‹€μ‹, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ³Έλ¬Έ

πŸ–₯ BE λ°±μ—”λ“œ/Java μžλ°”

[Java] λžŒλ‹€μ‹, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

λΉ„λΉ„ bibi 2021. 2. 23. 23:18

λžŒλ‹€

μ°Έκ³  :
''μžλ°”μ˜ 정석'' 을 보고 κ³΅λΆ€ν–ˆμŠ΅λ‹ˆλ‹€.

λžŒλ‹€μ‹ Lambda expression

JDK1.8λΆ€ν„° λ„μž…λœ κ°œλ…μ΄λ‹€.
λžŒλ‹€μ‹μ˜ λ„μž…μœΌλ‘œ μžλ°”λŠ” 객체지ν–₯언어인 λ™μ‹œμ— ν•¨μˆ˜ν˜• μ–Έμ–΄κ°€ λ˜μ—ˆλ‹€.

λžŒλ‹€μ‹μ΄λž€?

: λ©”μ„œλ“œλ₯Ό ν•˜λ‚˜μ˜ 식(expression)으둜 ν‘œν˜„ν•œ 것.
λžŒλ‹€μ‹μœΌλ‘œ ν•¨μˆ˜λ₯Ό κ°„λž΅ν•œ μ‹μœΌλ‘œ ν‘œν˜„ν•  수 μžˆλ‹€.
(λžŒλ‹€μ‹μ€ 읡λͺ…ν΄λž˜μŠ€μ˜ 객체와 λ™λ“±ν•˜λ‹€)

  • λ©”μ„œλ“œλ₯Ό λžŒλ‹€μ‹μœΌλ‘œ ν‘œν˜„ν•˜λ©΄ λ©”μ„œλ“œ 이름과 리턴값이 없어진닀.
    λ•Œλ¬Έμ— λžŒλ‹€μ‹μ„ '읡λͺ… ν•¨μˆ˜ anonymous function' 라고도 ν•œλ‹€.
(i) -> (int)(Math.random()*5)+1;

int method() {
    return (int)(Math.random()*5) + 1;
}

μœ„μ˜ λžŒλ‹€μ‹κ³Ό μ•„λž˜μ˜ method()λŠ” κ°™λ‹€.

λžŒλ‹€μ‹μ˜ μž₯점

  • λ©”μ„œλ“œλ³΄λ‹€ κ°„κ²°ν•˜λ©΄μ„œ λ©”μ„œλ“œμ˜ 역할을 λŒ€μ‹ ν•œλ‹€.

    • λ©”μ„œλ“œλŠ” ν΄λž˜μŠ€μ— ν¬ν•¨λ˜μ–΄μ•Ό ν•˜λ―€λ‘œ 클래슀λ₯Ό μƒˆλ‘œ λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.
      λžŒλ‹€μ‹μ€ 클래슀λ₯Ό μƒˆλ‘œ λ§Œλ“€ ν•„μš”κ°€ μ—†λ‹€.
    • λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κΈ° μœ„ν•΄ 객체도 생성해야 ν•œλ‹€.
      λžŒλ‹€μ‹μ€ 객체λ₯Ό 생성할 ν•„μš”κ°€ μ—†λ‹€.
  • λžŒλ‹€μ‹μ€ λ©”μ„œλ“œμ˜ λ§€κ°œλ³€μˆ˜λ‘œ 전달될 수 μžˆλ‹€.
    λžŒλ‹€μ‹μ€ λ©”μ„œλ“œμ˜ 결과둜 λ°˜ν™˜λ  수 μžˆλ‹€.

    β†’ λžŒλ‹€μ‹μœΌλ‘œ 인해 μžλ°”μ—μ„œλ„ λ©”μ„œλ“œλ₯Ό λ³€μˆ˜μ²˜λŸΌ λ‹€λ£° 수 있게 λ˜μ—ˆλ‹€. (ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° κ°€λŠ₯, ν•¨μˆ˜κ°€ 1κΈ‰ 객체)

λ©”μ„œλ“œμ™€ ν•¨μˆ˜μ˜ μ°¨μ΄λŠ”?

λ©”μ„œλ“œλŠ” ν•¨μˆ˜μ™€ λΉ„μŠ·ν•œ μ˜λ―Έμ΄μ§€λ§Œ,

  • λ©”μ„œλ“œλŠ” 객체지ν–₯ κ°œλ… 쀑 ν•˜λ‚˜λ‘œ 객체의 ν–‰μœ„λ₯Ό μ˜λ―Έν•˜λŠ” μš©μ–΄μ΄λ‹€.
  • λ©”μ„œλ“œλŠ” νŠΉμ • ν΄λž˜μŠ€μ— λ°˜λ“œμ‹œ 속해야 ν•œλ‹€λŠ” μ œμ•½μ΄ μžˆλ‹€.

λžŒλ‹€μ‹μœΌλ‘œ λ©”μ„œλ“œκ°€ ν•˜λ‚˜μ˜ 독립적 κΈ°λŠ₯을 ν•˜κΈ° λ•Œλ¬Έμ—, λ©”μ„œλ“œμ—μ„œ λ‹€μ‹œ ν•¨μˆ˜λΌκ³  λΆ€λ₯΄κ²Œ 됨.

λžŒλ‹€μ‹ μž‘μ„±ν•˜κΈ°

λžŒλ‹€μ‹μ€ '읡λͺ… ν•¨μˆ˜'μ΄λ―€λ‘œ,

  • λ©”μ„œλ“œμ—μ„œ '이름'κ³Ό 'λ¦¬ν„΄νƒ€μž…'을 μ œκ±°ν•œλ‹€.

  • λ§€κ°œλ³€μˆ˜ μ„ μ–ΈλΆ€()와 λͺΈν†΅{} 사이에 ->λ₯Ό μΆ”κ°€ν•œλ‹€.

  • λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ€ 좔둠이 κ°€λŠ₯ν•œ 경우 μƒλž΅ν•  수 μžˆλŠ”λ°, λŒ€λΆ€λΆ„μ˜ 경우 μƒλž΅ κ°€λŠ₯ν•˜λ‹€.

    λ¦¬ν„΄νƒ€μž… μ—­μ‹œ λŒ€λΆ€λΆ„μ˜ 경우 좔둠이 κ°€λŠ₯ν•˜λ―€λ‘œ μƒλž΅ν•œλ‹€.

    (int a, int b) -> a > b ? a : b -> (a, b) -> a > b? a : b

  • λ§€κ°œλ³€μˆ˜κ°€ ν•˜λ‚˜λΏμΈ 경우 ()λ₯Ό μƒλž΅ν•  수 μžˆλ‹€.

    단, λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ΄ 있으면 μƒλž΅ν•  수 μ—†λ‹€.

    (a) -> a * a -> a -> a * a (β­•)

    (int a) -> a * a -> int a -> a * a (❌)

  • λͺΈν†΅{} μ•ˆμ˜ λ¬Έμž₯이 ν•œ 쀄인 경우 {}λ₯Ό μƒλž΅ν•  수 μžˆλ‹€.

    이 λ•Œ λ¬Έμž₯의 끝에 ;λ₯Ό 뢙이지 μ•Šμ•„μ•Ό ν•œλ‹€.
    (String name, int i) -> { System.out.println(name + "=" + i); }

    -> (String name, int i) -> System.out.println(name + "=" + i)(β­•)

  • λͺΈν†΅{}μ•ˆμ˜ λ¬Έμž₯이 return문인 경우 {}λ₯Ό μƒλž΅ν•  수 μ—†λ‹€.

    (int a, int b) -> { return a > b ? a : b; }

    -> (int a, int b) -> return a > b ? a : b (❌)

    • returnλ¬Έμ—μ„œ, returnλŒ€μ‹  식(expression)으둜 λŒ€μ‹ ν•  수 μžˆλ‹€.

      (a, b) -> { return a > b ? a : b; } -> (a, b) -> a > b ? a : b

      • μ‹μ˜ μ—°μ‚°κ²°κ³Όκ°€ μžλ™μœΌλ‘œ 리턴값이 λœλ‹€.
      • λ¬Έμž₯이 μ•„λ‹Œ μ‹μ΄λ―€λ‘œ 끝에 ;λ₯Ό 뢙이지 μ•ŠλŠ”λ‹€.
    λ¦¬ν„΄νƒ€μž… λ©”μ„œλ“œμ΄λ¦„ (λ§€κ°œλ³€μˆ˜) { ... } // 일반 λ©”μ„œλ“œ
    
    (λ§€κ°œλ³€μˆ˜) -> { ... } // λžŒλ‹€μ‹
    int max(int a, int b) {
        return a > b ? a : b;
    } // λ©”μ„œλ“œ
    
    (int a, int b) -> {
        return a > b ? a : b;
    } // λžŒλ‹€μ‹
    
    new Object() {
        int max(int a, int b) {
            return a > b ? a : b;
        }
    } // λžŒλ‹€μ‹μ€ 사싀 λ©”μ„œλ“œκ°€ μ•„λ‹Œ, '읡λͺ…ν΄λž˜μŠ€μ˜ 객체'와 λ™λ“±ν•œ κ°œλ…μ΄λ‹€. (μ•„λž˜ λ‚΄μš© μ°Έμ‘°)

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ Functional Interface

μžλ°”μ—μ„œ λͺ¨λ“  λ©”μ„œλ“œλŠ” ν΄λž˜μŠ€μ— ν¬ν•¨λ˜μ–΄μ•Ό ν•œλ‹€. κ·Έλ ‡λ‹€λ©΄ λžŒλ‹€μ‹μ€ μ–΄λ–€ ν΄λž˜μŠ€μ— ν¬ν•¨λ˜λŠ” 것인가?

β†’ λžŒλ‹€μ‹μ€ 읡λͺ… 클래슀의 객체, 즉 읡λͺ… 객체이닀.

(사싀 λžŒλ‹€μ‹μ€ λ©”μ„œλ“œμ™€ λ™λ“±ν•œ 것이 μ•„λ‹Œ, 읡λͺ…ν΄λž˜μŠ€μ˜ 객체와 λ™λ“±ν•œ 것이닀)

λžŒλ‹€μ‹μ€ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 읡λͺ… 객체λ₯Ό λŒ€μ²΄ν•  수 μžˆλ‹€.

단, 읡λͺ… 객체의 λ©”μ„œλ“œμ™€ λžŒλ‹€μ‹μ˜ λ§€κ°œλ³€μˆ˜ νƒ€μž…, λ§€κ°œλ³€μˆ˜ 개수, 리턴값이 μΌμΉ˜ν•΄μ•Ό ν•œλ‹€.

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λž€..

: λžŒλ‹€μ‹μ„ 닀루기 μœ„ν•œ μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€.

μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 읡λͺ…객체λ₯Ό λžŒλ‹€μ‹μœΌλ‘œ λŒ€μ²΄ κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ—, μΈν„°νŽ˜μ΄μŠ€λ₯Ό 톡해 λžŒλ‹€μ‹μ„ λ‹€λ£¨κ²Œ λ˜μ—ˆλ‹€.

  • (쑰건) ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ—λŠ” 였직 ν•˜λ‚˜μ˜ μΆ”μƒλ©”μ„œλ“œλ§Œ μ •μ˜λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.

    κ·Έλž˜μ•Ό λžŒλ‹€μ‹κ³Ό μΈν„°νŽ˜μ΄μŠ€μ˜ λ©”μ„œλ“œκ°€ 1:1둜 연결될 수 있기 λ•Œλ¬Έ.

    (staticλ©”μ„œλ“œ, defaultλ©”μ„œλ“œ κ°œμˆ˜μ—λŠ” μ œν•œμ΄ μ—†λ‹€)

    @FuncionalInterface
    interface MyFunction {
        public abstract int max(int a, int b);
    } // ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ MyFunction을 μ •μ˜ν•œ μ˜ˆμ‹œ. μ–΄λ…Έν…Œμ΄μ…˜μ„ κΌ­ λΆ™μ΄μž.
  • λ©”μ„œλ“œ ν•˜λ‚˜λΏμΈ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•  λ•Œ μ•„λž˜μ™€ 같이 κ°„λ‹¨ν•˜κ²Œ λ§Œλ“€ 수 있게 λœλ‹€.

    List<String> list = Arrays.asList("aaa", "bbb", "ccc");
    Collections.sort(list, new Comparator<String>() {
        public int compare(String s1, String s2) {
            return s2.compareTo(s1);
        }
    }); // ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ‚¬μš© μ „
    
    List<String> list = Arrays.asList("aaa", "bbb", "ccc");
    Collections.sort(list, (s1, s2) -> s2.compareTo(s1)); // ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ‚¬μš© ν›„

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ λ§€κ°œλ³€μˆ˜ νƒ€μž…κ³Ό λ¦¬ν„΄νƒ€μž…

λžŒλ‹€μ‹μ€ μ°Έμ‘°λ³€μˆ˜λ‘œ λ‹€λ£° 수 μžˆλ‹€. 즉, λ©”μ„œλ“œλ₯Ό 톡해 λžŒλ‹€μ‹μ„ λ³€μˆ˜μ²˜λŸΌ 주고받을 수 있게 λ˜μ—ˆλ‹€.

(사싀 λ©”μ„œλ“œκ°€ μ•„λ‹Œ 객체λ₯Ό μ£Όκ³ λ°›λŠ” 것이기 λ•Œλ¬Έμ— 근본적으둜 달라진 것은 μ—†μ§€λ§Œ, μ½”λ“œκ°€ κ°„κ²°ν•˜κ³  μ‰¬μ›Œμ‘Œλ‹€λŠ” μž₯점이 μžˆλ‹€)

  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ©”μ„œλ“œμ˜ λ§€κ°œλ³€μˆ˜ νƒ€μž…μ„, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μžμ‹ μœΌλ‘œ μ •μ˜ν•  수 μžˆλ‹€.

    ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•  λ•Œ λžŒλ‹€μ‹μ„ μ°Έμ‘°ν•˜λŠ” μ°Έμ‘°λ³€μˆ˜λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ 지정해야 ν•œλ‹€.

    @FunctionalInterface
    interface MyFunction {
        void myMethod(); // 좔상 λ©”μ„œλ“œ
    
        void aMethod(MyFunction f) { // λ§€κ°œλ³€μˆ˜νƒ€μž…μ„ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μžμ‹ μœΌλ‘œ 지정
            f.myMethod(); // MyFunctionμ—μ„œ μ •μ˜λœ λ©”μ„œλ“œ 호좜
        }
    }
    MyFunction f = () -> System.out.println("myMethod()");
    aMethod(f); 
    aMethod(() -> System.out.println("myMethod()"))
    // aMethodλ₯Ό ν˜ΈμΆœν•  λ•ŒλŠ” λžŒλ‹€μ‹μ„ μ°Έμ‘°ν•˜λŠ” μ°Έμ‘°λ³€μˆ˜λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ 지정해야 함
  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ©”μ„œλ“œμ˜ λ¦¬ν„΄νƒ€μž…μ„, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μžμ‹ μœΌλ‘œ μ •μ˜ν•  수 μžˆλ‹€.

    ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΆ”μƒλ©”μ„œλ“œμ™€ λ™λ“±ν•œ λžŒλ‹€μ‹μ„ κ°€λ¦¬ν‚€λŠ” μ°Έμ‘°λ³€μˆ˜λ₯Ό λ°˜ν™˜ν•˜κ±°λ‚˜, λžŒλ‹€μ‹μ„ 직접 λ°˜ν™˜ν•  수 μžˆλ‹€.

    @FunctionalInterface
    interface MyFunction {
        void myMethod(); // 좔상 λ©”μ„œλ“œ
    
        MyFunction aMethod() { // λ¦¬ν„΄νƒ€μž…μ„ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μžμ‹ μœΌλ‘œ 지정
            MyFunction f = () -> {};
            return f;
            // return () -> {}; 둜 쀄일 수 μžˆλ‹€.
        }
    }

λžŒλ‹€μ‹μ˜ νƒ€μž…κ³Ό ν˜•λ³€ν™˜

  • λžŒλ‹€μ‹μ€ 읡λͺ… 객체이고, 읡λͺ… κ°μ²΄λŠ” νƒ€μž…μ΄ μ—†λ‹€.

    (μ •ν™•νžˆλŠ” νƒ€μž…μ€ μžˆμ§€λ§Œ, μ»΄νŒŒμΌλŸ¬κ°€ μž„μ˜λ‘œ 이름을 μ •ν•˜λ―€λ‘œ μ•Œ 수 μ—†λ‹€)

    ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‘œ λžŒλ‹€μ‹μ„ μ°Έμ‘°ν•  μˆ˜λŠ” μžˆμ§€λ§Œ, λžŒλ‹€μ‹μ˜ νƒ€μž…μ΄ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ νƒ€μž…κ³Ό μΌμΉ˜ν•˜λŠ” 것은 μ•„λ‹ˆλ‹€.

    λ”°λΌμ„œ μ›λž˜λŠ” μ•„λž˜μ™€ 같은 ν˜•λ³€ν™˜μ΄ ν•„μš”ν•˜λ‹€.

    interface MyFunction {
        void method();
    }
    
    MyFunction f = (MyFunction) (() -> {}); // μ–‘λ³€μ˜ νƒ€μž…μ΄ λ‹€λ₯΄λ―€λ‘œ ν˜•λ³€ν™˜ ν•„μš”.

    λžŒλ‹€μ‹μ€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό 직접 κ΅¬ν˜„ν•˜μ§„ μ•Šμ•˜μ§€λ§Œ, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 클래슀의 객체와 μ™„μ „νžˆ λ™μΌν•˜κΈ° λ•Œλ¬Έμ— 이런 ν˜•λ³€ν™˜μ΄ κ°€λŠ₯ν•˜λ‹€.

    또, 이 ν˜•λ³€ν™˜μ€ μƒλž΅ κ°€λŠ₯ν•˜λ‹€.

  • λžŒλ‹€μ‹μ€ κ°μ²΄μ΄μ§€λ§Œ 였직 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‘œλ§Œ ν˜•λ³€ν™˜μ΄ κ°€λŠ₯ν•˜λ‹€.

    즉 λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ 직접 ν˜•λ³€ν™˜ ν•  수 μ—†λ‹€.

    λžŒλ‹€μ‹μ„ λ‹€λ₯Έ νƒ€μž…μœΌλ‘œ ν˜•λ³€ν™˜ν•˜κΈ° μœ„ν•΄μ„œλŠ”, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‘œ ν˜•λ³€ν™˜ν•œ λ‹€μŒ κ·Έ 객체λ₯Ό λ‹€μ‹œ ν˜•λ³€ν™˜ν•΄μ•Ό ν•œλ‹€.

    Object obj = (Object) (()->{}); // μ—λŸ¬
    Object obj = (Object) (MyFunction) (()->{}); // λžŒλ‹€μ‹μ„ Object둜 ν˜•λ³€ν™˜
    String str = ((Object) (MyFunction) (()->{})).toString(); // λžŒλ‹€μ‹μ„ String으둜 ν˜•λ³€ν™˜

λžŒλ‹€μ‹μœΌλ‘œ μ™ΈλΆ€ λ³€μˆ˜ μ°Έμ‘°

λžŒλ‹€μ‹μ€ 읡λͺ… 객체, 즉 읡λͺ… 클래슀의 μΈμŠ€ν„΄μŠ€μ΄λ‹€.

λ”°λΌμ„œ μ™ΈλΆ€ λ³€μˆ˜μ— μ ‘κ·Όν•˜λŠ” κ·œμΉ™λ„ 읡λͺ…ν΄λž˜μŠ€μ˜ 방식과 λ™μΌν•˜λ‹€.

  • λžŒλ‹€μ‹ λ‚΄μ—μ„œ μ°Έμ‘°ν•˜λŠ” μ§€μ—­λ³€μˆ˜λŠ” final이 뢙지 μ•Šμ•„λ„ μƒμˆ˜λ‘œ κ°„μ£Όλœλ‹€.

    λžŒλ‹€μ‹ λ‚΄μ—μ„œλ‚˜ λ‹€λ₯Έ κ³³μ—μ„œλ„ 이 λ³€μˆ˜μ˜ 값을 λ³€κ²½ν•  수 μ—†λ‹€.

  • μ™ΈλΆ€ μ§€μ—­λ³€μˆ˜μ™€ 같은 μ΄λ¦„μ˜ λžŒλ‹€μ‹ λ§€κ°œλ³€μˆ˜λŠ” ν—ˆμš©λ˜μ§€ μ•ŠλŠ”λ‹€.

(~ 'μžλ°”μ˜ 정석 2' p.802κΉŒμ§€ 정리함)