lambda and closure jihoon - GANGNAM-JAVA/JAVA-STUDY GitHub Wiki

λžŒλ‹€ λŒ€μˆ˜

  1. λžŒλ‹€ λŒ€μˆ˜λŠ” 이름을 κ°€μ§ˆ ν•„μš”κ°€ μ—†λ‹€.(읡λͺ… ν•¨μˆ˜)
  2. 두 개 μ΄μƒμ˜ μž…λ ₯이 μžˆλŠ” ν•¨μˆ˜λŠ” μ΅œμ’…μ μœΌλ‘œ 1개의 μž…λ ₯만 λ°›λŠ” λžŒλ‹€ λŒ€μˆ˜λ‘œ λ‹¨μˆœν™” 될 수 μžˆλ‹€.(컀링)

읡λͺ… ν•¨μˆ˜(Anonymous function)

  • 읡λͺ… ν•¨μˆ˜λŠ” λžŒλ‹€ λŒ€μˆ˜λ‘œλΆ€ν„° 영ν–₯을 λ°›μ•„ λ§Œλ“€μ–΄μ§„ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ ν•¨μˆ˜λ₯Ό ν‘œν˜„ν•˜λŠ” λ°©μ‹μ˜ 일쒅.
  • Java8λΆ€ν„° μ§€μ›ν•˜κ²Œ 된 λžŒλ‹€κ°€ 읡λͺ… ν•¨μˆ˜λ₯Ό μ˜λ―Έν•œλ‹€.
  • 읡λͺ… ν•¨μˆ˜λ©΄μ„œ 일급 객체의 νŠΉμ§•μ„ 가지고 있으면 lambda라고 ν•  수 μžˆλ‹€.
    • 일급 κ°μ²΄λŠ” ν•¨μˆ˜μ˜ 인자둜 λ„˜κ²¨ 받을 μˆ˜λ„ 있으며, ν•¨μˆ˜μ˜ κ²°κ³Όκ°’μœΌλ‘œ 리턴할 μˆ˜λ„ 있고, λ³€μˆ˜μ— ν• λ‹Ήν•  μˆ˜λ„ μžˆλ‹€λŠ” 것을 λ§ν•œλ‹€.

λžŒλ‹€μ™€ ν΄λ‘œμ €

function adder(a) {
  return function(b) {
    return a + b;
  }
}

var add5 = adder(5);
add5(10); // 15

ν΄λ‘œμ €λŠ” λžŒλ‹€λ‘œλΆ€ν„° νŒŒμƒλœ κ°œλ…μ΄λ‹€.
add5λΌλŠ” ν•¨μˆ˜μ˜ μž…μž₯μ—μ„œ 생각해볼 λ•Œ, μžμ‹ μ˜ μŠ€μ½”ν”„ 내에 μžˆλŠ” bλΌλŠ” λ³€μˆ˜λŠ” 인자둜 받은 λ³€μˆ˜μ΄κ³  ν•΄λ‹Ή μŠ€μ½”ν”„ 내에 κ°‡ν˜€μžˆμ§€λ§Œ, aλΌλŠ” λ³€μˆ˜λŠ” λŒ€μ²΄ μ–΄λ””μ„œ μ™€μ„œ μ‚¬μš©λ˜κ³  μžˆλŠ”μ§€ μ•Œ μˆ˜κ°€ μ—†λ‹€. μ΄λ•Œμ˜ aλ₯Ό 자유 λ³€μˆ˜(Free variable), bλ₯Ό 묢인 λ³€μˆ˜(Bound variable) 라고 λΆ€λ₯Έλ‹€.

μœ„μ˜ λžŒλ‹€μ‹μ—μ„œλŠ” 자유 λ³€μˆ˜μ™€ 묢인 λ³€μˆ˜λ₯Ό ν•˜λ‚˜μ”© μ‚¬μš©ν•˜κ³  μžˆλ‹€. λžŒλ‹€μ‹μ€ μ‚¬μš©ν•˜λŠ” λ³€μˆ˜μ˜ μ’…λ₯˜μ— 따라 두 μ’…λ₯˜λ‘œ λ‚˜λˆŒ 수 μžˆλ‹€. λ°”λ‘œ λ‹«νžŒ λžŒλ‹€μ‹(Closed expression)κ³Ό μ—΄λ¦° λžŒλ‹€μ‹(Open expression) 이닀.

λžŒλ‹€ ν‘œν˜„μ‹μ—μ„œ μ‚¬μš©ν•˜λŠ” λ³€μˆ˜λ“€μ΄ λͺ¨λ‘ 묢인 λ³€μˆ˜μΌ λ•Œ, λ‹«νžŒ λžŒλ‹€μ‹μ΄λΌκ³  λΆ€λ₯Έλ‹€. 그리고 λžŒλ‹€ ν‘œν˜„μ‹μ—μ„œ μ‚¬μš©ν•˜λŠ” λ³€μˆ˜λ“€ 쀑 ν•˜λ‚˜λΌλ„ 자유 λ³€μˆ˜κ°€ μžˆμ„ λ•Œ μ—΄λ¦° λžŒλ‹€μ‹μ΄λΌκ³  λΆ€λ₯Έλ‹€.

ν΄λ‘œμ €λŠ” μ΄λ¦„μ²˜λŸΌ λ°”λ‘œ μ—΄λ¦° λžŒλ‹€μ‹μ„ λ‹«νžŒ λžŒλ‹€μ‹μœΌλ‘œ λ§Œλ“œλŠ” 것이닀. ν΄λ‘œμ €λŠ” λžŒλ‹€μ‹ λ‚΄μ˜ λͺ¨λ“  자유 λ³€μˆ˜λ₯Ό μŠ€μ½”ν”„ λ‚΄λ‘œ 가져와 λ¬ΆλŠ”λ‹€. κ·Έλ ‡κΈ° λ•Œλ¬Έμ— ν΄λ‘œμ €λŠ” λ§Œλ“€μ–΄μ§„ ν™˜κ²½μ„ κΈ°μ–΅ν•˜λŠ” κ²ƒμ²˜λŸΌ 보인닀.

MDNμ—μ„œμ˜ μ •μ˜
ν΄λ‘œμ €λŠ” 독립적인 (자유) λ³€μˆ˜λ₯Ό κ°€λ¦¬ν‚€λŠ” ν•¨μˆ˜μ΄λ‹€. λ˜λŠ”, ν΄λ‘œμ € μ•ˆμ— μ •μ˜λœ ν•¨μˆ˜λŠ” λ§Œλ“€μ–΄μ§„ ν™˜κ²½μ„ β€˜κΈ°μ–΅ν•œλ‹€β€™.

Java λžŒλ‹€

읡λͺ… ν΄λž˜μŠ€λ³΄λ‹€ 더 κ°„λž΅ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•˜μ—¬ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ„ ν•  수 μžˆλ„λ‘ λ„μ™€μ£ΌλŠ” κΈ°λŠ₯이닀.
ν•¨μˆ˜λ₯Ό λ³€μˆ˜μ²˜λŸΌ μ‚¬μš©ν•˜μ—¬ νŒŒλΌλ―Έν„° λ‹€λ₯Έ λ©”μ„œλ“œμ˜ 인자둜 전달할 수 있고, 리턴 κ°’μœΌλ‘œ ν•¨μˆ˜λ₯Ό 받을 μˆ˜λ„ μžˆλ‹€.
μžλ°”μ˜ λžŒλ‹€μ‹μ€ ν•¨μˆ˜ν˜•μ— λŒ€ν•΄ μƒˆλ‘œ μ •μ˜ν•œ 것이 μ•„λ‹Œ, 기쑴에 μ‘΄μž¬ν•˜λŠ” interface의 ν˜•νƒœλ₯Ό λΉŒμ–΄ λžŒλ‹€μ‹μ„ ν‘œν˜„ν•˜κΈ° λ•Œλ¬Έμ— ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ˜ μž₯정을 μ™„μ „νžˆ κ°€μ§€μ§€λŠ” λͺ» ν•œλ‹€.

  • 기쑴의 읡λͺ… ν΄λž˜μŠ€λ°©μ‹
new Thread(new Runnable() { 
    public void run() {
        System.out.println("Annoymous Thread");
    }
}).start();
  • λžŒλ‹€λ°©μ‹
new Thread(() -> System.out.println("Lambda Thread")).start();

μœ„μ—μ„œ λžŒλ‹€μ‹μ— ν•΄λ‹Ήν•˜λŠ” 뢀뢄은 μ•„λž˜κ³Ό κ°™λ‹€.

()->System.out.println("Lambda Thread")
  • () λŠ” νŒŒλΌλ―Έν„°μ— ν•΄λ‹Ήν•˜λŠ”λ°, run() μ΄λΌλŠ” 읡λͺ…ν΄λž˜μŠ€μ˜ λ©”μ†Œλ“œκ°€ μ•„λ¬΄λŸ° νŒŒλΌλ―Έν„°λ₯Ό μ·¨ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” μ˜λ―Έμ΄λ‹€.
  • -> λŠ” λžŒλ‹€μ‹ μ‹œμž‘ 전에 λ‚˜νƒ€λ‚˜λŠ” λžŒλ‹€μ‹ μ‹œμž‘ 토큰이닀. λ’€μ—λŠ” ν•œμ€„μ§œλ¦¬ λžŒλ‹€μ‹ ν˜Ήμ€ { } μ•ˆμ— ν¬ν•¨λœ μ—¬λŸ¬ λžŒλ‹€μ‹λ“€μ΄ 올수 μžˆλ‹€.
  • System.out.println("Lambda Thread") λŠ” λžŒλ‹€μ‹μ˜ λ‚΄μš© λΆ€λΆ„μœΌλ‘œ, 이 μ•ˆμ—λŠ” νŒŒλΌλ―Έν„° 값이 μ‚¬μš©λ μˆ˜ μžˆλ‹€.

λžŒλ‹€μ‹μ€ Interface ν˜•νƒœλ‘œ λ³€μˆ˜λ‘œ 할당될 수 μžˆλ‹€. 즉, λžŒλ‹€μ‹ λ˜ν•œ 객체의 ν˜•νƒœλ₯Ό μ·¨ν•˜κ³  μžˆλ‹€λŠ” 의미이고, λžŒλ‹€μ‹μ—μ„œλŠ” ν•¨μˆ˜μ˜ 이름을 μ‚¬μš©ν•΄μ„œ λ‘œμ§μ„ μ„ μ–Έν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—, μΈν„°νŽ˜μ΄μŠ€μ—μ„œλ„ ν•¨μˆ˜μ˜ 이름이 ν•„μš”κ°€ 없을것 κ°™μ§€λ§Œ, μ˜ˆμ „ μžλ°”μ˜ λͺ¨λ“  것을 λ’€μ—Žμ„μˆ˜λŠ” μ—†κΈ° λ•Œλ¬Έμ— 기쑴의 객체 ν˜•νƒœλ‘€ 톡해 μΌμ’…μ˜ μ ˆμΆ©μ„ ν•˜μ˜€κ³ , 그것이 @FunctionalInterface λΌλŠ” μ–΄λ…Έν…Œμ΄μ…˜μ΄λ‹€.

// Runnable.java

package java.lang;

// μΈν„°νŽ˜μ΄μŠ€ μœ„μ— @FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜μ„ 톡해 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μž„μ„ μ„ μ–Έ
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
// Test.java

public class Test {
    private static Runnable lambdaTest(Runnable runnable) {
        runnable.run();
        return ()->System.out.println("return lambda");
    }

    public static void main(String argsp[]) {
        lambdaTest(()->System.out.println("input lambda")).run();
    }
}
/* 
κ²°κ³Ό)
input lambda
return lambda
*/

JDKμ—μ„œ 기본적으둜 μ§€μ›ν•˜λŠ”(built-in) ν‘œμ€€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ μžˆλ‹€.

  • java.util.function.UnaryOperator

    • ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜
    T apply(T t)
    • μΈμˆ˜κ°€ 1개이며, 리턴값과 인수의 νƒ€μž…μ΄ κ°™λ‹€.
  • java.util.function.BinaryOperator

    • ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜
    T apply(T t1, T t2)
    • μΈμˆ˜κ°€ 2개이며, 리턴값과 인수의 νƒ€μž…μ΄ κ°™λ‹€.
  • java.util.function.Predicate

    • ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜
    boolean test(T t)
    • μž„μ˜μ˜ νƒ€μž… ν˜•νƒœμ˜ κ°μ²΄μž…λ ₯을 λ°›μ•„ 그값을 μ²˜λ¦¬ν•œ ν›„ κ²°κ³Όκ°€ true인지 false 인지λ₯Ό λ¦¬ν„΄ν•œλ‹€.
  • java.util.function.Function<T,R>

    • ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜
    R apply(T t)
    • 첫번째 μž„μ˜μ˜ ν˜•νƒœμ˜ μž…λ ₯값을 λ°›μ•„ μ²˜λ¦¬ν•œν›„ λ‘λ²ˆμ§Έ μž„μ˜μ˜ ν˜•νƒœμ˜ κ°’μœΌλ‘œ 좜λ ₯ν•œλ‹€.
  • java.util.function.Supplier

    • ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜
    T get()
    • μž…λ ₯값은 λ”°λ‘œ μ—†μ§€λ§Œ, 좜λ ₯κ°’μ˜ ν˜•νƒœλ₯Ό μ§€μ •ν• μˆ˜ μžˆλ‹€.
  • java.util.function.Consumer

    • ν•¨μˆ˜ μ‹œκ·Έλ‹ˆμ²˜
    void accept(T t)
    • μž„μ˜ν˜•νƒœμ˜ μž…λ ₯값을 λ°›μ•„ μ²˜λ¦¬ν•˜κ³  좜λ ₯은 ν•˜μ§€ μ•ŠλŠ” ν˜•νƒœμ˜ μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€.

Java ν΄λ‘œμ €(closure)

λ³΄ν†΅μ˜ ν•¨μˆ˜λŠ” μ™ΈλΆ€μ—μ„œ 인자λ₯Ό λ°›μ•„μ„œ λ‘œμ§μ„ μ²˜λ¦¬ν•˜μ§€λ§Œ, ν΄λ‘œμ €λŠ” μžμ‹ μ„ λ‘˜λŸ¬μ‹Ό context λ‚΄μ˜ λ³€μˆ˜μ— μ ‘κ·Όν•  수 μžˆλ‹€.
즉, μ™ΈλΆ€ λ²”μœ„μ˜ λ³€μˆ˜λ₯Ό ν•¨μˆ˜ λ‚΄λΆ€λ‘œ λ°”μΈλ”©ν•˜λŠ” κΈ°μˆ μ΄λ‹€.

νŠΉμ΄ν•œ 점은 μžμ‹ μ„ λ‘˜λŸ¬μ‹Ό μ™ΈλΆ€ ν•¨μˆ˜κ°€ μ’…λ£Œλ˜λ”λΌλ„ 이 값이 μœ μ§€λœλ‹€λŠ” 것이닀. ν•¨μˆ˜μ—μ„œ μ‚¬μš©ν•˜λŠ” 값듀은 ν΄λ‘œμ €κ°€ μƒμ„±λ˜λŠ” μ‹œμ μ—μ„œ μ •μ˜λ˜κ³  ν•¨μˆ˜ μžμ²΄κ°€ λ³΅μ‚¬λ˜μ–΄ λ”°λ‘œ μ‘΄μž¬ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

// anonymous 클래슀의 closure 
private static Function<String, Integer> function() {
    int a = 100;
    return new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return Integer.parseInt(s) * a;
        }
    };
}

Function<String, Integer> function = function();
Integer apply = function.apply("3");
System.out.println(apply);
// lambda closure
private static Function<String ,Integer> function(){
    int a = 100;
    return s -> Integer.parseInt(s) * a;
}

Function<String, Integer> function = function();
Integer apply = function.apply("3");
System.out.println(apply);

μ°Έκ³ 

⚠️ **GitHub.com Fallback** ⚠️