Skip to content

Latest commit

Β 

History

History
878 lines (692 loc) Β· 33.5 KB

LambdaExpression.md

File metadata and controls

878 lines (692 loc) Β· 33.5 KB

읡λͺ… 클래슀 β†’ λžŒλ‹€ ν‘œν˜„μ‹ β†’ λ©”μ„œλ“œ μ°Έμ‘°

λžŒλ‹€ ν‘œν˜„μ‹

  • λžŒλ‹€κ°€ 기술적으둜 μžλ°” 8 μ΄μ „μ˜ λ°”λ‘œ ν•  수 μ—†μ—ˆλ˜ 일을 μ œκ³΅ν•˜λŠ” 것은 μ•„λ‹ˆλ‹€.
  • λ‹€λ§Œ λ™μž‘ νŒŒλΌλ―Έν„°λ₯Ό μ΄μš©ν•  λ•Œ 읡λͺ… 클래슀 λ“± νŒμ— λ°•νžŒ μ½”λ“œλ₯Ό κ΅¬ν˜„ν•  ν•„μš”κ°€ μ—†λ‹€.
  • λžŒλ‹€ ν‘œν˜„μ‹μ€ κ΄‘λ²”μœ„ν•˜κ²Œ μ‚¬μš©λ˜λ―€λ‘œ 이 μž₯의 λ‚΄μš©μ„ μ™„λ²½ν•˜κ²Œ 이해해야 ν•œλ‹€.

λžŒλ‹€μ˜ λͺ©ν‘œλŠ” 정해진 λ™μž‘μ„ λ‹€λ₯Έ λ©”μ„œλ“œμ—μ„œ μ‚¬μš©ν•  수 μžˆλ„λ‘ ν•˜λ‚˜μ˜ 쑰각으둜 μΊ‘μŠν™” ν•˜λŠ” 것이닀.
μ„ΈλΆ€ κ΅¬ν˜„μ„ ν¬ν•¨ν•˜λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ„ κ³΅κ°œν•˜μ§€ 말아야 ν•œλ‹€.

λžŒλ‹€μ˜ κΈ°λ³Έ 문법

  • ν‘œν˜„μ‹ μŠ€νƒ€μΌ
    • (parameters) -> expression
    • return을 λͺ…μ‹œν•˜μ§€ μ•ŠλŠ”λ‹€.
  • 블둝 μŠ€νƒ€μΌ
    • (parameters) -> { statements; }
    • λͺ…μ‹œμ μœΌλ‘œ return문을 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

λžŒλ‹€λž€ 무엇인가?

  • λžŒλ‹€ ν‘œν˜„μ‹μ€ λ©”μ„œλ“œλ‘œ 전달할 수 μžˆλŠ” 읡λͺ… ν•¨μˆ˜λ₯Ό λ‹¨μˆœν™”ν•œ 것이라고 ν•  수 μžˆλ‹€.
  • λžŒλ‹€μ˜ νŠΉμ§•
    1. 읡λͺ…
      • λ³΄ν†΅μ˜ λ©”μ„œλ“œμ™€ 달리 이름이 μ—†μœΌλ―€λ‘œ 읡λͺ…이라 ν‘œν˜„ν•œλ‹€.
    2. ν•¨μˆ˜
      • λžŒλ‹€λŠ” λ©”μ„œλ“œμ²˜λŸΌ νŠΉμ • ν΄λž˜μŠ€μ— μ’…μ†λ˜μ§€ μ•ŠμœΌλ―€λ‘œ ν•¨μˆ˜λΌκ³  λΆ€λ₯Έλ‹€.
      • ν•˜μ§€λ§Œ λ©”μ„œλ“œ 처럼 νŒŒλΌλ―Έν„° 리슀트 , λ°”λ”” , λ°˜ν™˜ ν˜•μ‹ , λ°œμƒν•  수 μžˆλŠ” μ˜ˆμ™Έ λ¦¬μŠ€νŠΈλŠ” κ°€μ§ˆ 수 μžˆλ‹€.
    3. 전달
      • λžŒλ‹€ ν‘œν˜„μ‹μ„ λ©”μ„œλ“œ 인수둜 μ „λ‹¬ν•˜κ±°λ‚˜ λ³€μˆ˜λ‘œ μ €μž₯ν•  수 μžˆλ‹€.
    4. κ°„κ²°μ„±
      • 읡λͺ… 클래슀처럼 λ§Žμ€ μžμ§ˆκ΅¬λ ˆν•œ μ½”λ“œλ₯Ό κ΅¬ν˜„ν•  ν•„μš”κ°€ μ—†λ‹€.
  • Comparatorλ₯Ό κ΅¬ν˜„ν•˜λŠ” κΈ°μ‘΄ μ½”λ“œ
Comparator<Apple> byWeight = new Comparator<Apple>(){
    public int compare(Apple a1 , Apple a2){
        return a1.getWeight().compareTo(a2.getWeight());
    }
};
  • λžŒλ‹€λ₯Ό μ‚¬μš©ν•œ μ½”λ“œ
Comparator<Apple> byWeight = (Apple a1 , Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

  • λžŒλ‹€ νŒŒλΌλ―Έν„°
    • Comparator의 compareλ©”μ„œλ“œ νŒŒλΌλ―Έν„°
  • ν™”μ‚΄ν‘œ
    • λžŒλ‹€μ˜ νŒŒλΌλ―Έν„° λ¦¬μŠ€νŠΈμ™€ λ°”λ””λ₯Ό κ΅¬λΆ„ν•œλ‹€.
  • λžŒλ‹€ λ°”λ””
    • 두 사과 무게λ₯Ό λΉ„κ΅ν•œλ‹€. λžŒλ‹€μ˜ λ°˜ν™˜κ°’μ— ν•΄λ‹Ήν•˜λŠ” ν‘œν˜„μ‹μ΄λ‹€.

λžŒλ‹€ ν‘œν˜„μ‹ 예제

(String s) -> s.length
  • String ν˜•μ‹μ˜ νŒŒλΌλ―Έν„° ν•˜λ‚˜λ₯Ό 가지며 intλ₯Ό λ°˜ν™˜ν•œλ‹€.
  • λžŒλ‹€ ν‘œν˜„μ‹μ—λŠ” return이 ν•¨μΆ•λ˜μ–΄ μžˆμœΌλ―€λ‘œ return 문을 λͺ…μ‹œμ μœΌλ‘œ μ‚¬μš©ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.
(Apple a) -> a.getWeight() > 150
  • Appleν˜•μ‹μ˜ νŒŒλΌλ―Έν„° ν•˜λ‚˜λ₯Ό 가지며 boolean을 λ°˜ν™˜ν•œλ‹€.
(int x , int y) -> {
    System.out.println("Result : " + x + y);
}
  • intν˜•μ‹μ˜ νŒŒλΌλ―Έν„° 두 개λ₯Ό 가지며 void 리턴이닀.
  • λžŒλ‹€ ν‘œν˜„μ‹μ€ μ—¬λŸ¬ ν–‰μ˜ λ¬Έμž₯을 포함할 수 μžˆλ‹€.
() -> 42
  • νŒŒλΌλ―Έν„°κ°€ μ—†μœΌλ©° int 42λ₯Ό λ°˜ν™˜ν•œλ‹€.

어디에 , μ–΄λ–»κ²Œ λžŒλ‹€λ₯Ό μ‚¬μš©ν• κΉŒ?

  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λΌλŠ” λ¬Έλ§₯μ—μ„œ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•  수 μžˆλ‹€.

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

  • μ •ν™•νžˆ ν•˜λ‚˜μ˜ 좔상 λ©”μ„œλ“œλ₯Ό μ§€μ •ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€
  • πŸ“Œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‘œ 뭘 ν•  수 μžˆμ„κΉŒ?
    • λžŒλ‹€ ν‘œν˜„μ‹μœΌλ‘œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œ κ΅¬ν˜„μ„ 직접 전달할 수 μžˆμœΌλ―€λ‘œ 전체 ν‘œν˜„μ‹μ„ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ‘œ μ·¨κΈ‰ν•  수 μžˆλ‹€.
    • 기술적으둜 따지면 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 클래슀의 μΈμŠ€ν„΄μŠ€
// java.util.Comparator
public interface Comparator<T>{
    int compare(T o1 , T o2);
}

// java.lang.Runnable
public interface Runnable{
    void run();
}

// java.awt.event.ActionListener
public interface ActionListener extends EventListener{
    void actionPerformed(ActionEvent e);
}

// java.util.concurrent.Callable
public interface Callable<V>{
    V call() thorws Exception;
}

// java.security.PrivilegedAction
public interface PrivilegedAction<T>{
    T run();
}

μΈν„°νŽ˜μ΄μŠ€λŠ” λ””ν΄νŠΈ λ©”μ„œλ“œ (μΈν„°νŽ˜μ΄μŠ€μ˜ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜μ§€ μ•Šμ€ 클래슀λ₯Ό κ³ λ €ν•΄μ„œ κΈ°λ³Έ κ΅¬ν˜„μ„ μ œκ³΅ν•˜λŠ” λ°”λ””λ₯Ό ν¬ν•¨ν•˜λŠ” λ©”μ„œλ“œ) λ₯Ό 포함할 수 μžˆλ‹€.
πŸ“Œ λ§Žμ€ λ””ν΄νŠΈ λ©”μ„œλ“œκ°€ μžˆλ”λΌλ„ 좔상 λ©”μ„œλ“œκ°€ 였직 ν•˜λ‚˜ 이면 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‹€.
μžμ‹ μΈν„°νŽ˜μ΄μŠ€κ°€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μΈ λΆ€λͺ¨ μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν™•μž₯ν•˜κ²Œ 되면 μžμ‹ μΈν„°νŽ˜μ΄μŠ€λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ μ•„λ‹ˆλ‹€.

  • Runnable이 였직 ν•˜λ‚˜μ˜ 좔상 λ©”μ„œλ“œ run을 μ •μ˜ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ΄λ―€λ‘œ μ•„λž˜ μ˜ˆμ œλŠ” μ˜¬λ°”λ₯Έ κ΅¬ν˜„ μ½”λ“œμ΄λ‹€.
class Main {
    public static void main(String[] args) throws IOException {
        // λžŒλ‹€ μ‚¬μš©
        Runnable r1 = () -> System.out.println("Hello World");

        // 읡λͺ… 클래슀 μ‚¬μš©
        Runnable r2 = new Runnable(){
            public void run(){
                System.out.println("Hello World 2");
            }
        };

        process(r1);
        process(r2);
        // 직접 μ „λ‹¬λœ λžŒλ‹€ ν‘œν˜„μ‹
        process(() -> System.out.println("Hello World 3"));

        // Hello World
        // Hello World 2
        // Hello World 3        
    }

    public static void process(Runnable r){
        r.run();
    }
}

μ™œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό 인수둜 λ°›λŠ” λ©”μ„œλ“œμ—λ§Œ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•  수 μžˆμ„κΉŒ?

  • μ–Έμ–΄ μ„€κ³„μžλ“€μ€ ν•¨μˆ˜ ν˜•μ‹(λžŒλ‹€ ν‘œν˜„μ‹μ„ ν‘œν˜„ν•˜λŠ”λ° μ‚¬μš©ν•œ μ‹œκ·Έλ‹ˆμ²˜μ™€ 같은 νŠΉλ³„ν•œ ν‘œκΈ°λ²•)을 μΆ”κ°€ν•˜λŠ” 방법도 λŒ€μ•ˆμœΌλ‘œ κ³ λ €ν–ˆλ‹€.
  • ν•˜μ§€λ§Œ μ–Έμ–΄ μ„€κ³„μžλ“€μ€ μ–Έμ–΄λ₯Ό 더 λ³΅μž‘ν•˜κ²Œ λ§Œλ“€μ§€ μ•ŠλŠ” ν˜„μž¬ 방법을 μ„ νƒν–ˆλ‹€.
  • 어디에 λžŒλ‹€λ₯Ό μ‚¬μš©ν•  수 μžˆμ„κΉŒ?
1. 
    execute(() -> {});
    public void execute(Runnable r){
        r.run();
    }

2. 
    public Callable<String> fetch(){
        return () -> "Tricky Example";
    }
    System.out.println(fetch().call());

3. 
    Predicate<Apple> p = (Apple a) -> a.getWeight();
    
  • 1번과 2λ²ˆμ€ μœ νš¨ν•œ λžŒλ‹€ ν‘œν˜„μ‹μ΄λ‹€.
  • () -> {}의 μ‹œκ·Έλ‹ˆμ²˜λŠ” () -> voidλ©° Runnable의 좔상 λ©”μ„œλ“œ run의 μ‹œκ·Έλ‹ˆμ²˜μ™€ μΌμΉ˜ν•˜λ―€λ‘œ μœ νš¨ν•œ λžŒλ‹€ ν‘œν˜„μ‹μ΄λ‹€.
  • Callable<String>의 μ‹œκ·Έλ‹ˆμ²˜λŠ” () -> String이 λœλ‹€.
  • (Apple a) -> a.getWeight() λŠ” (Apple) -> Integerμ΄λ―€λ‘œ Predicate의 μ‹œκ·Έλ‹ˆμ²˜μ™€ μΌμΉ˜ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μœ νš¨ν•˜μ§€ μ•Šλ‹€.
@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

βœ‹ @FunctionalInterfaceλŠ” 무엇인가?

  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μž„μ„ κ°€λ¦¬ν‚€λŠ” μ–΄λ…Έν…Œμ΄μ…˜μ΄λ‹€.
  • @FunctionalInterface둜 μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ„ μ–Έν–ˆμ§€λ§Œ μ‹€μ œλ‘œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ μ•„λ‹ˆλ©΄ μ»΄νŒŒμΌλŸ¬κ°€ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.
  • 예λ₯Όλ“€μ–΄ , 좔상 λ©”μ„œλ“œκ°€ ν•œ 개 이상이라면 "Multiple nonoverriding abstract methods found int interface Foo"(μΈν„°νŽ˜μ΄μŠ€ Foo에 μ˜€λ²„λΌμ΄λ“œ ν•˜μ§€ μ•Šμ€ μ—¬λŸ¬ 좔상 λ©”μ„œλ“œκ°€ μžˆλ‹€) 같은 μ—λŸ¬κ°€ λ°œμƒν•  수 μžˆλ‹€.

λžŒλ‹€ ν™œμš© : μ‹€ν–‰ μ–΄λΌμš΄λ“œ νŒ¨ν„΄

  • λžŒλ‹€μ™€ λ™μž‘ νŒŒλΌλ―Έν„°ν™”λ‘œ μœ μ—°ν•˜κ³  κ°„κ²°ν•œ μ½”λ“œλ₯Ό κ΅¬ν˜„ν•˜λŠ” 데 도움을 주느 μ‹€μš©μ μΈ 예제λ₯Ό μ‚΄νŽ΄λ³΄μž
  • μžμ› 처리 (예λ₯Ό λ“€λ©΄ , 데이터 베이슀의 파일처리)에 μ‚¬μš©ν•˜λŠ” μˆœν™˜ νŒ¨ν„΄μ€ μžμ›μ„ μ—΄κ³  , μ²˜λ¦¬ν•œ λ‹€μŒμ— , μžμ›μ„ λ‹«λŠ” μˆœμ„œλ‘œ 이루어진닀.
  • 즉 , μ‹€μ œ μžμ›μ„ μ²˜λ¦¬ν•˜λŠ” μ½”λ“œλ₯Ό μ„€μ •κ³Ό 정리 두 과정이 λ‘˜λŸ¬μ‹ΈλŠ” ν˜•νƒœλ₯Ό μ‹€ν–‰ μ–΄λΌμš΄λ“œ νŒ¨ν„΄μ΄λΌκ³  λΆ€λ₯Έλ‹€.
public String processFile() throws IOException {
    try(BufferedReader br = new BufferedReader(new FileReader("data.txt"))){
        return br.readLine();
    }
}
  • βœ‹ ν•΄λ‹Ή μ˜ˆμ œλŠ” μžλ°” 7에 μƒˆλ‘œ μΆ”κ°€λœ try-with-resourcesλ₯Ό μ‚¬μš©ν–ˆλ‹€.

1단계 : λ™μž‘ νŒŒλΌλ―Έν„°ν™”λ₯Ό κΈ°μ–΅ν•˜λΌ

  • ν˜„μž¬ μ½”λ“œλŠ” νŒŒμΌμ—μ„œ ν•œ λ²ˆμ— ν•œ μ€„λ§Œ 읽을 수 μžˆλ‹€.
  • ν•œ λ²ˆμ— 두 쀄을 μ½κ±°λ‚˜ κ°€μž₯ 자주 μ‚¬μš©λ˜λŠ” 단어λ₯Ό λ°˜ν™˜ν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Όν• κΉŒ?
  • 기쑴의 μ„€μ • , 정리 과정은 μž¬μ‚¬μš©ν•˜κ³  processFileλ©”μ„œλ“œμ˜ λ™μž‘μ„ νŒŒλΌλ―Έν„°ν™” ν•΄μ•Όν•œλ‹€.
String result = processFile((BufferedReader br) -> br.readLine() + br.readLine());

2단계 : ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ΄μš©ν•΄μ„œ λ™μž‘ 전달

  • BufferedReader -> Stringκ³Ό IOException을 던질 수 μžˆλŠ” μ‹œκ·Έλ‹ˆμ²˜μ™€ μΌμΉ˜ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€μ–΄ processFileλ©”μ„œλ“œμ˜ 인수둜 전달할 수 μžˆλ‹€.
@FunctionalInterface
public interface BufferedReaderProcessor{
    String process(BufferedReader br) throws IOException;
}

public String processFile(BufferedReaderProcessor p) throws Exception {
    // do something ...
}

3단계 : λ™μž‘ μ‹€ν–‰

  • process λ©”μ„œλ“œμ˜ μ‹œκ·Έλ‹ˆμ²˜ (BufferedReader -> String)κ³Ό μΌμΉ˜ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό λžŒλ‹€ ν‘œν˜„μ‹μœΌλ‘œ 좔상 λ©”μ„œλ“œ κ΅¬ν˜„μ„ 직접 전달할 수 μžˆλ‹€.
  • μ „λ‹¬λœ μ½”λ“œλŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ‘œ μ „λ‹¬λœ μ½”λ“œμ™€ 같은 λ°©μ‹μœΌλ‘œ μ²˜λ¦¬ν•œλ‹€.
public String processFile(BufferedReaderProcessr p) throws IOException{
    try(BufferedReader br = new BufferedReader(new FileReader("data.txt"))){
        return p.process(br);
    }
}

4단계 : λžŒλ‹€ 전달

  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό λžŒλ‹€λ‘œ μΈμŠ€ν„΄μŠ€ν™” ν•΄μ„œ λ‹€μ–‘ν•œ λ™μž‘μ„ processFile λ©”μ„œλ“œλ‘œ 전달할 수 μžˆλ‹€.
// ν•œ 행을 μ²˜λ¦¬ν•˜λŠ” μ½”λ“œ
String oneLine = processFile((BufferedReader br) -> br.readLine());

// 두 행을 μ²˜λ¦¬ν•˜λŠ” μ½”λ“œ
String twoLines = processFile((BufferedReader br) -> br.readLine() + br.readLine());

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ μ‚¬μš©

  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” 였직 ν•˜λ‚˜μ˜ 좔상 λ©”μ„œλ“œλ₯Ό μ§€μ •ν•œλ‹€.
  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œλŠ” λžŒλ‹€ ν‘œν˜„μ‹μ˜ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό 가리킀며 ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λΌκ³  ν•œλ‹€.
  • λ‹€μ–‘ν•œ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•˜λ €λ©΄ κ³΅ν†΅μ˜ ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λ₯Ό κΈ°μˆ ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ 집합이 ν•„μš”ν•˜λ‹€.
  • java.util.function νŒ¨ν‚€μ§€λ‘œ μ—¬λŸ¬κ°€μ§€ μƒˆλ‘œμš΄ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ œκ³΅ν•œλ‹€.

Predicate<T>

  • μ œλ„€λ¦­ ν˜•μ‹ T의 객체λ₯Ό 인수둜 λ°›μ•„ boolean을 λ°˜ν™˜ν•˜λŠ” testλΌλŠ” 좔상 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•œλ‹€.
public <T> List<T> filter(List<T> list , Predicate<T> p){
    List<T> results = new ArrayList<>();
    for(T t : list){
        if(p.test(t)) results.add(t);
    }
    return results;
}

Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(listOfStrings , nonEmptyStringPredicate);

Consumer<T>

  • μ œλ„€λ¦­ ν˜•μ‹ T의 객체λ₯Ό 인수둜 λ°›μ•„ void을 λ°˜ν™˜ν•˜λŠ” acceptλΌλŠ” 좔상 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•œλ‹€.
  • Tν˜•μ‹μ˜ 객체λ₯Ό 인수둜 λ°›μ•„μ„œ μ–΄λ–€ λ™μž‘μ„ μˆ˜ν–‰ν•˜κ³  싢을 λ•Œ ConsumerλΌλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.
public <T> void forEach(List<T> list , Consumer<T> c){
    for(T t : list){
        c.accept(t);
    }
}

forEach(
    Arrays.asList(1,2,3,4,5),
    System.out::println // Consumer의 acceptλ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜λŠ” λžŒλ‹€
);

Function<T , R>

  • μ œλ„€λ¦­ ν˜•μ‹ Tλ₯Ό 인수둜 λ°›μ•„ R 객체λ₯Ό λ°˜ν™˜ν•˜λŠ” applyλΌλŠ” 좔상 λ©”μ„œλ“œλ₯Ό μ •μ˜ν•œλ‹€.
  • μž…λ ₯을 좜λ ₯으둜 λ§€ν•‘ν•˜λŠ” λžŒλ‹€λ₯Ό μ •μ˜ν•  λ•Œ FunctionμΈν„°νŽ˜μ΄μŠ€λ₯Ό ν™œμš©ν•  수 μžˆλ‹€.
    • μ‚¬κ³Όμ˜ 무게 정보λ₯Ό μΆ”μΆœν•˜κ±°λ‚˜ , λ¬Έμžμ—΄μ„ 길이와 맀핑
@FunctionalInterface
public interface Function<T , R>{
    R apply(T t);
}

public <T , R> List<R> map(List<T> list , Function<T , R> f){
    List<R> result = new ArrayList<>();
    for(T t : list){
        result.add(f.apply(t));
    }
    return result;
}

List<Integer> list = map(
    Arrays.asList("lambdas" , "in" , "action"),
    (String s) -> s.length()
);

κΈ°λ³Έν˜• νŠΉν™”

  • μžλ°”μ˜ λͺ¨λ“  ν˜•μ‹μ€ μ°Έμ‘°ν˜• (Byte , Integer , Object , List...) μ•„λ‹ˆλ©΄ κΈ°λ³Έν˜• (int , double , byte , char...)에 ν•΄λ‹Ήν•œλ‹€.
// int ➜ Integer μ˜€ν† λ°•μ‹±
List<Integer> list = new ArrayList<>();
for(int i = 300 ; i < 400 ; i++){
    list.add(i);
}
  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μ œλ„€λ¦­ νŒŒλΌλ―Έν„°μ—λŠ” μ°Έμ‘°ν˜•λ§Œ μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ— μœ„μ™€ 같은 μ˜€ν† λ°•μ‹± λ³€ν™˜ 과정을 μˆ˜ν–‰ν•˜λŠ” λΉ„μš©μ΄ μ†Œλͺ¨λœλ‹€.
    • λ°•μ‹±ν•œ 값은 κΈ°λ³Έν˜•μ„ κ°μ‹ΈλŠ” 래퍼며 νž™μ— μ €μž₯λœλ‹€.
    • λ”°λΌμ„œ λ°•μ‹±ν•œ 값은 λ©”λͺ¨λ¦¬λ₯Ό 더 μ†ŒλΉ„ν•˜λ©° κΈ°λ³Έν˜•μ„ κ°€μ Έμ˜¬ λ•Œλ„ λ©”λͺ¨λ¦¬λ₯Ό νƒμƒ‰ν•˜λŠ” 과정이 ν•„μš”ν•˜λ‹€.
  • πŸ“Œ μžλ°” 8 μ—μ„œλŠ” κΈ°λ³Έν˜•μ„ μž…μΆœλ ₯으둜 μ‚¬μš©ν•˜λŠ” μƒν™©μ—μ„œ μ˜€ν† λ°•μ‹± λ™μž‘μ„ ν”Όν•  수 μžˆλ„λ‘ νŠΉλ³„ν•œ λ²„μ „μ˜ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ œκ³΅ν•œλ‹€.
public interface IntPredicate{
    boolean test(int t);
}

IntPredicate evenNumbers = (int i) -> i % 2 == 0;
evenNumbers.test(1000);

Predicate<Integer> oddNumbers = (Integer i) -> i % 2 != 0;
oddNumbers.test(1000);

예제

  • T -> R
    • Function<T , R>이 λŒ€ν‘œμ μΈ μ˜ˆμ œλ‹€.
    • Tν˜•μ‹μ˜ 객체λ₯Ό Rν˜•μ‹μ˜ 객체둜 λ³€ν™˜ν•  λ•Œ μ‚¬μš©ν•œλ‹€.
  • (int , int) -> int
    • IntBinaryOperatorλŠ” (int , int) -> intν˜•μ‹μ˜ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό κ°–λŠ” 좔상 λ©”μ„œλ“œ applyAsIntλ₯Ό μ •μ˜ν•œλ‹€.
  • () -> T
    • Supplier<T>λŠ” () -> Tν˜•μ‹μ˜ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό κ°–λŠ” 좔상 λ©”μ„œλ“œ get을 μ •μ˜ν•œλ‹€.
    • Callable<T>도 () -> Tν˜•μ‹μ˜ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό κ°–λŠ” 좔상 λ©”μ„œλ“œ call을 μ •μ˜ν•œλ‹€.
  • (T , U) -> R
    • BiFunction<T , U , R>은 (T , U) -> Rν˜•μ‹μ˜ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό κ°–λŠ” 좔상 λ©”μ„œλ“œ applyλ₯Ό μ •μ˜ν•œλ‹€.
// booleanν‘œν˜„
// 1. λžŒλ‹€ 예제
(List<String> list) -> list.isEmpty()

// 2. λŒ€μ‘ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€
Predicate<List<String>>

// 객체 생성
// 1. λžŒλ‹€ 예제
() -> new Apple(10)

// 2. λŒ€μ‘ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€
Supplier<Apple>

// κ°μ²΄μ—μ„œ μ†ŒλΉ„
// 1. λžŒλ‹€ 예제
(Apple a) -> System.out.println(a.getWeight())

// 2. λŒ€μ‘ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€
Consumer<Apple>

// κ°μ²΄μ—μ„œ 선택/μΆ”μΆœ
// 1. λžŒλ‹€ 예제
(String s) -> s.length()

// 2. λŒ€μ‘ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€
Function<String , Integer> λ˜λŠ”
ToIntFunction<String>

// 두 κ°’ μ‘°ν•©
// 1. λžŒλ‹€ 예제
(int a , int b) -> a * b

// 2. λŒ€μ‘ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€
intBinaryOperator

// 두 객체 비ꡐ
// 1. λžŒλ‹€ 예제
(Apple a1 , Apple a2) -> a1.getWeight().compareTo(a2.getWeight())

// 2. λŒ€μ‘ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€
Comparator<Apple> λ˜λŠ”
BiFunction<Apple , Apple , Integer> λ˜λŠ”
ToIntBiFunction<Apple , Apple>

// μ˜ˆμ™Έλ₯Ό λ˜μ§€λŠ” λžŒλ‹€ ν‘œν˜„μ‹
// 1. ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ—μ„œ 직접 μ •μ˜
public String processFile(BufferedReaderProcessr p) throws IOException{
    try(BufferedReader br = new BufferedReader(new FileReader("data.txt"));){
        return p.process(br);
    }
}

// 2. try/catch 블둝
Function<BufferedReader , String> f = (BufferedReader b) -> {
    try{
        return b.readLine();
    }
    catch(IOException e){
        throw new RuntimeException(e);
    }
};

ν˜•μ‹ 검사 , ν˜•μ‹ μΆ”λ‘  , μ œμ•½

  • μ»΄νŒŒμΌλŸ¬κ°€ λžŒλ‹€μ˜ ν˜•μ‹μ„ μ–΄λ–»κ²Œ ν™•μΈν•˜λŠ”μ§€, ν”Όν•΄μ•Ό ν•  사항은 무엇인지 μ•Œμ•„λ³΄μž.
  • λžŒλ‹€ ν‘œν˜„μ‹ μžμ²΄μ—λŠ” λžŒλ‹€κ°€ μ–΄λ–€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ”μ§€μ˜ 정보가 ν¬ν•¨λ˜μ–΄ μžˆμ§€ μ•Šλ‹€.
  • λžŒλ‹€μ˜ μ‹€μ œ ν˜•μ‹μ„ νŒŒμ•…ν•΄λ³΄μž

ν˜•μ‹ 검사

  • λžŒλ‹€κ°€ μ‚¬μš©λ˜λŠ” μ½˜ν…μŠ€νŠΈλ₯Ό μ΄μš©ν•΄μ„œ λžŒλ‹€μ˜ ν˜•μ‹μ„ μΆ”λ‘ ν•  수 μžˆλ‹€.
  • μ–΄λ–€ μ½˜ν…μŠ€νŠΈ (λžŒλ‹€κ°€ μ „λ‹¬λœ λ©”μ„œλ“œ νŒŒλΌλ―Έν„°λ‚˜ λžŒλ‹€κ°€ ν• λ‹Ήλ˜λŠ” λ³€μˆ˜ λ“±) μ—μ„œ κΈ°λŒ€λ˜λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ˜ ν˜•μ‹μ„ λŒ€μƒ ν˜•μ‹μ΄λΌκ³  λΆ€λ₯Έλ‹€.
List<Apple> heavierThan150g = filter(inventory , (Apple apple) -> apple.getWeight() > 150);

  • λŒ€μƒ ν˜•μ‚­ : Predicate<Apple>
  • ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„° : (Apple) -> Boolean

같은 λžŒλ‹€ , λ‹€λ₯Έ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

  • λŒ€μƒ ν˜•μ‹μ΄λΌλŠ” νŠΉμ§• λ•Œλ¬Έμ— 같은 λžŒλ‹€ ν‘œν˜„μ‹μ΄λ”λΌλ„ ν˜Έν™˜λ˜λŠ” 좔상 λ©”μ„œλ“œλ₯Ό 가진 λ‹€λ₯Έ ν•¨μˆ˜λ₯Ό μΈν„°νŽ˜μ΄μŠ€λ‘œ μ‚¬μš©λ  수 μžˆλ‹€.
  • 즉, ν•˜λ‚˜μ˜ λžŒλ‹€ ν‘œν˜„μ‹μ„ λ‹€μ–‘ν•œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ— μ‚¬μš©ν•  수 μžˆλ‹€.
Comparator<Apple> c1 = (Apple a1 , Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
ToIntBiFunction<Apple , Apple> c2 = (Apple a1 , Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
BiFunction<Apple , Apple , Integer> c3 = (Apple a1 , Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

같은 ν•¨μˆ˜ν˜• λ””μŠ€ν¬λ¦½ν„°λ₯Ό 가진 두 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ°–λŠ” λ©”μ†Œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ”© ν•  λ•Œ, μ–΄λ–€ λ©”μ†Œλ“œμ˜ μ‹œκ·Έλ‹ˆμ²˜κ°€ μ‚¬μš©λ˜μ–΄μ•Ό ν•˜λŠ”μ§€λ₯Ό λͺ…μ‹œμ μœΌλ‘œ κ΅¬λΆ„ν•˜λ„λ‘ λžŒλ‹€λ₯Ό μΊμŠ€νŒ… ν•  수 μžˆλ‹€.

@FunctionalInterface
interface Action {
    void act();
}

public void execute(Runnable runnable) {
    runnable.run();
}

public void execute(Action<T> action) {
    action.act();
}

execute((Runnable) () -> {});
execute((Action) () -> {});

ν˜•μ‹ μΆ”λ‘ 

  • μžλ°” μ»΄νŒŒμΌλŸ¬λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ΄ μ‚¬μš©λœ μ½˜ν…μŠ€νŠΈ(λŒ€μƒ ν˜•μ‹)을 μ΄μš©ν•΄μ„œ λžŒλ‹€ ν‘œν˜„μ‹κ³Ό κ΄€λ ¨λœ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μΆ”λ‘ ν•œλ‹€.
  • 즉, λŒ€μƒ ν˜•μ‹μ„ μ΄μš©ν•΄μ„œ ν•¨μˆ˜ λ””μŠ€ν¬λ¦½ν„°λ₯Ό μ•Œ 수 μžˆμœΌλ―€λ‘œ μ»΄νŒŒμΌλŸ¬λŠ” λžŒλ‹€μ˜ μ‹œκ·Έλ‹ˆμ²˜λ„ μΆ”λ‘ ν•  수 μžˆλ‹€.
  • 결과적으둜 μ»΄νŒŒμΌλŸ¬λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ˜ νŒŒλΌλ―Έν„° ν˜•μ‹μ— μ ‘κ·Όν•  수 μžˆμœΌλ―€λ‘œ λžŒλ‹€ λ¬Έλ²•μ—μ„œ 이λ₯Ό μƒλž΅ν•  수 μžˆλ‹€.
Comparator<Apple> c1 = (a1 , a2) -> a1.getWeight().compareTo(a2.getWeight());

지역 λ³€μˆ˜ μ‚¬μš© λ³€μˆ˜ 캑쳐

  • λžŒλ‹€ ν‘œν˜„μ‹μ—μ„œλŠ” 읡λͺ… ν•¨μˆ˜κ°€ ν•˜λŠ” κ²ƒμ²˜λŸΌ **자유 λ³€μˆ˜ (νŒŒλΌλ―Έν„°λ‘œ λ„˜κ²¨μ§„ λ³€μˆ˜κ°€ μ•„λ‹Œ μ™ΈλΆ€μ—μ„œ μ •μ˜λœ λ³€μˆ˜)**λ₯Ό ν™œμš©ν•  수 μžˆλ‹€.
  • 이와 같은 λ™μž‘μ„ λžŒλ‹€ 캑쳐링이라고 λΆ€λ₯Έλ‹€.
int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber);
portNumber = 3338;
  • μ§€μ—­λ³€μˆ˜λŠ” λͺ…μ‹œμ μœΌλ‘œ final둜 μ„ μ–Έλ˜μ–΄ μžˆμ–΄μ•Ό ν•˜κ±°λ‚˜ , μ‹€μ§ˆμ μœΌλ‘œ final둜 μ„ μ–Έλœ λ³€μˆ˜μ™€ λ˜‘κ°™μ΄ μ‚¬μš©λ˜μ–΄μ•Ό ν•œλ‹€.
  • μœ„μ˜ μ˜ˆμ œλŠ” 컴파일 ν•  수 μ—†λ‹€.

지역 λ³€μˆ˜μ˜ μ œμ•½

  • μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λŠ” νž™μ— μœ„μΉ˜ν•˜λ©° , 지역 λ³€μˆ˜λŠ” μŠ€νƒμ— μœ„μΉ˜ν•œλ‹€.
  • λžŒλ‹€κ°€ μŠ€λ ˆλ“œμ—μ„œ μ‹€ν–‰λœλ‹€λ©΄ λ³€μˆ˜λ₯Ό ν• λ‹Ήν•œ μŠ€λ ˆλ“œκ°€ μ‚¬λΌμ Έμ„œ λ³€μˆ˜ 할당이 ν•΄μ œλ˜μ—ˆλŠ”λ°λ„ λžŒλ‹€λ₯Ό μ‹€ν–‰ν•˜λŠ” μŠ€λ ˆλ“œμ—μ„œλŠ” ν•΄λ‹Ή λ³€μˆ˜μ— μ ‘κ·Όν•˜λ € ν•  수 μžˆλ‹€.
  • λ”°λΌμ„œ μžλ°” κ΅¬ν˜„μ—μ„œλŠ” μ›λž˜ λ³€μˆ˜μ— 접근을 ν—ˆμš©ν•˜λŠ” 것이 μ•„λ‹ˆλΌ 자유 지역 λ³€μˆ˜μ˜ 볡사본을 μ œκ³΅ν•œλ‹€.
    • λ³΅μ‚¬λ³Έμ˜ 값이 λ°”λ€Œμ§€ μ•Šμ•„μ•Ό ν•˜λ―€λ‘œ 지역 λ³€μˆ˜μ—λŠ” ν•œ 번만 값을 ν• λ‹Ήν•΄μ•Ό ν•œλ‹€λŠ” μ œμ•½μ΄ 생긴 것이닀.
  • 병렬화λ₯Ό λ°©ν•΄ν•˜λŠ” μš”μ†Œκ°€ 될 μˆ˜λ„ μžˆλ‹€.

λ©”μ„œλ“œ μ°Έμ‘°

  • νŠΉμ • λ©”μ„œλ“œλ§Œμ„ ν˜ΈμΆœν•˜λŠ” λžŒλ‹€μ˜ μΆ•μ•½ν˜•μ΄λΌκ³  생각할 수 μžˆλ‹€.
  • λ©”μ €λ“œ μ°Έμ‘°λ₯Ό μ΄μš©ν•˜λ©΄ κΈ°μ‘΄ λ©”μ„œλ“œ κ΅¬ν˜„μœΌλ‘œ λžŒλ‹€ ν‘œν˜„μ‹μ„ λ§Œλ“€ 수 μžˆλ‹€.
  • λ©”μ„œλ“œλͺ… μ•žμ— κ΅¬λΆ„μž ::λ₯Ό λΆ™μ΄λŠ” λ°©μ‹μœΌλ‘œ λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό ν™œμš©ν•  수 μžˆλ‹€.
  • μ‹€μ œλ‘œ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” 것은 μ•„λ‹ˆλ―€λ‘œ κ΄„ν˜ΈλŠ” ν•„μš” μ—†μŒμ„ κΈ°μ–΅ν•˜μž
  • λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μƒˆλ‘œμš΄ κΈ°λŠ₯이 μ•„λ‹ˆλΌ ν•˜λ‚˜μ˜ λ©”μ„œλ“œλ₯Ό μ°Έμ‘°ν•˜λŠ” λžŒλ‹€λ₯Ό νŽΈλ¦¬ν•˜κ²Œ ν‘œν˜„ν•  수 μžˆλŠ” λ¬Έλ²•μœΌλ‘œ 가독성을 높일 수 μžˆλ‹€.
λžŒλ‹€ λ©”μ„œλ“œ μ°Έμ‘° 단좕 ν‘œν˜„
(Apple apple) -> apple.getWeight() Apple::getWeight
() -> Thread.currentThread().dumpStack() Thread.currentThread()::dumpStack
(str , i) -> str.substring(i) String::substring
(String s) -> System.out.println(s) System.out::println
(String s) -> this.isValidName(s) this::isValidName

λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό λ§Œλ“œλŠ” 방법

  1. 정적 λ©”μ„œλ“œ μ°Έμ‘°
    • Integer::parseInt ...
  2. λ‹€μ–‘ν•œ ν˜•μ‹μ˜ μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œ μ°Έμ‘°
    • String의 lengthλ©”μ„œλ“œλŠ” String::length
  3. κΈ°μ‘΄ 객체의 μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œ μ°Έμ‘°
    • Transactionν΄λž˜μŠ€μ—λŠ” getValueλ©”μ„œλ“œκ°€ 있고 ν•΄λ‹Ή 클래슀λ₯Ό ν• λ‹Ή 받은 expensiveTransaction지역 λ³€μˆ˜κ°€ μžˆλ‹€.
    • 이λ₯Ό expensiveTransaction::getValueν‘œν˜„ν•  수 μžˆλ‹€.

List<String> str = Arrays.asList("a" , "b" , "A" , "B");
str.sort((s1 , s2) -> s1.compareToIgnoreCase(s2));
str.sort(String::compareToIgnoreCase);

1.  ToIntFunction<String> stringToInt = (String s) -> Integer.parseInt(s);
    ToIntFunction<String> stringToInt = Integer::parseInt;

2.  BiPredicate<List<String> , String> contains = (list , element) -> list.contains(element);
    BiPredicate<List<String> , String> contains = List::contains;

3.  // λΉ„κ³΅κ°œ 헬퍼 λ©”μ„œλ“œ 호좜
    class test{
        Predicate<String> startsWithNumber = (String string) -> this.startsWithNumber(string);
        Predicate<String> startsWithNumber2 = this::startsWithNumber;

        private boolean startsWithNumber(String string) {
            return true;
        }
    }

μƒμ„±μž μ°Έμ‘°

  • ClassName::new처럼 클래슀λͺ…κ³Ό newν‚€μ›Œλ“œλ₯Ό μ΄μš©ν•΄μ„œ κΈ°μ‘΄ μƒμ„±μžμ˜ μ°Έμ‘°λ₯Ό λ§Œλ“€ 수 μžˆλ‹€.
  • 이것은 정적 λ©”μ„œλ“œμ˜ μ°Έμ‘°λ₯Ό λ§Œλ“œλŠ” 방법과 λΉ„μŠ·ν•˜λ‹€.
  • 예λ₯Ό λ“€μ–΄ μΈμˆ˜κ°€ μ—†λŠ” μƒμ„±μž , Supplier의 () -> Appleκ³Ό 같은 μ‹œκ·Έλ‹ˆμ²˜λ₯Ό κ°–λŠ” μƒμ„±μžκ°€ μžˆλ‹€κ³  κ°€μ •ν•˜μž.
@FunctionalInterface
public interface TriFunction<T , U , V , R> {
    R get(T t, U u, V v);
}

class Apple{
    int weight;
    Color color;
    String status;
    int objectHashCode = this.hashCode();

    public Apple() {
    }
    public Apple(int weight) {
        this.weight = weight;
    }
    public Apple(int weight, Color color) {
        this.weight = weight;
        this.color = color;
    }
    public Apple(int weight, String status) {
        this.weight = weight;
        this.status = status;
    }
    public Apple(int weight, Color color, String status) {
        this.weight = weight;
        this.color = color;
        this.status = status;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "weight=" + weight +
                ", color='" + color + '\'' +
                ", status='" + status + '\'' +
                ", objectHashCode=" + objectHashCode +
                '}';
    }
    public enum Color {GREEN , RED , YELLOW}
}

class Main {
    public static void main(String[] args) throws Exception {
        Supplier<Apple> supplier1 = Apple::new;
        System.out.println(supplier1.get());

        Supplier<Apple> supplier2 = () -> new Apple();
        System.out.println(supplier2.get());

        Function<Integer , Apple> function1 = Apple::new;
        System.out.println(function1.apply(11));

        List<Integer> weights = Arrays.asList(21 , 22 , 23 , 24 , 25);
        List<Apple> apples = map(weights , function1);
        apples.forEach(System.out::println);

        BiFunction<Integer , Apple.Color, Apple> biFunction1 = Apple::new;
        System.out.println(biFunction1.apply(31 , Apple.Color.GREEN));

        BiFunction<Integer , String , Apple> biFunction2 = Apple::new;
        System.out.println(biFunction2.apply(41 , "GOOD"));

        TriFunction<Integer , Apple.Color , String , Apple> triFunction1 = Apple::new;
        System.out.println(triFunction1.get(51 , Apple.Color.RED , "BAD"));

//        Apple{weight=0, color='null', status='null', objectHashCode=1854731462}
//        Apple{weight=0, color='null', status='null', objectHashCode=214126413}
//        Apple{weight=11, color='null', status='null', objectHashCode=1867750575}
//        Apple{weight=21, color='null', status='null', objectHashCode=2046562095}
//        Apple{weight=22, color='null', status='null', objectHashCode=1342443276}
//        Apple{weight=23, color='null', status='null', objectHashCode=769287236}
//        Apple{weight=24, color='null', status='null', objectHashCode=1587487668}
//        Apple{weight=25, color='null', status='null', objectHashCode=1199823423}
//        Apple{weight=31, color='GREEN', status='null', objectHashCode=1896277646}
//        Apple{weight=41, color='null', status='GOOD', objectHashCode=1702297201}
//        Apple{weight=51, color='RED', status='BAD', objectHashCode=1296064247}

    }

    public static List<Apple> map(List<Integer> list , Function<Integer , Apple> f){
        List<Apple> result = new ArrayList<>();
        for(Integer i : list){
            result.add(f.apply(i));
        }
        return result;
    }
}
  • μΈμŠ€ν„΄μŠ€ν™” ν•˜μ§€ μ•Šκ³ λ„ μƒμ„±μžμ— μ ‘κ·Όν•  수 μžˆλŠ” κΈ°λŠ₯을 λ‹€μ–‘ν•œ 상황에 μ‘μš©ν•  수 μžˆλ‹€.
  • 예λ₯Ό λ“€μ–΄ Map으둜 μƒμ„±μžμ™€ λ¬Έμžμ—΄ 값을 κ΄€λ ¨μ‹œν‚¬ 수 μžˆλ‹€.
  • 그리고 Stringκ³Ό Integerκ°€ μ£Όμ–΄μ‘Œμ„ λ•Œ λ‹€μ–‘ν•œ 무게λ₯Ό κ°–λŠ” μ—¬λŸ¬ μ’…λ₯˜μ˜ 과일을 λ§Œλ“œλŠ” giveMeFruitλ©”μ„œλ“œλ₯Ό λ§Œλ“€ 수 μžˆλ‹€.
static Map<String , Function<Integer , Fruit>> map = new HashMap<>();
static{
    map.put("apple" , Apple::new);
    map.put("orange" , Orange::new);
    ...
}

public static Fruit giveMeFruit(String fruit , Integer weight){
    return map.get(fruit.toLowerCase()) // mapμ—μ„œ Function<Integer , Fruit>을 μ–»μ—ˆλ‹€.
                .apply(weight);           // Function의 applyλ©”μ„œλ“œμ— μ •μˆ˜λ₯Ό μ œκ³΅ν•˜μ—¬ Fruit을 생성할 수 μžˆλ‹€.
}

λžŒλ‹€ , λ©”μ„œλ“œ μ°Έμ‘° ν™œμš©ν•˜κΈ°

1단계 : μ½”λ“œ 전달

  • sort의 λ™μž‘μ€ νŒŒλΌλ―Έν„°ν™”λ˜μ—ˆλ‹€. (μ •λ ¬ μ „λž΅μ— 따라 λ™μž‘μ΄ 달라진닀.)
// List.sort의 μ‹œκ·Έλ‹ˆμ²˜
void sort(Comparator<? super E> c)

public class AppleComparator implements Comparator<Apple>{
    public int compare(Apple a1 , Apple a2){
        return a1.getWeight().compareTo(a2.getWeight());
    }
}
inventory.sort(new AppleComparator());

2단계 : 읡λͺ… 클래슀 μ‚¬μš©

  • ν•œ 번만 μ‚¬μš©ν•  Comparatorλ₯Ό κ΅¬ν˜„ν•˜κΈ° λ³΄λ‹€λŠ” 읡λͺ… 클래슀λ₯Ό μ΄μš©ν•˜λŠ” 것이 μ’‹λ‹€.
inventory.sort(new Comparator<Apple>(){
    public int compare(Apple a1 , Apple a2){
        return a1.getWeight().compareTo(a2.getWeight());
    }
});

3단계 : λžŒλ‹€ ν‘œν˜„μ‹ μ‚¬μš©

  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κΈ°λŒ€ν•˜λŠ” κ³³ μ–΄λ””μ—λ‚˜ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•  수 μžˆλ‹€.
inventory.sort((Apple a1 , Apple a2) ->> a1.getWeight().compareTo(a2.getWeight()));    
  • μžλ°” μ»΄νŒŒμΌλŸ¬λŠ” λžŒλ‹€ ν‘œν˜„μ‹μ΄ μ‚¬μš©λœ μ½˜ν…μŠ€νŠΈλ₯Ό ν™œμš©ν•΄μ„œ λžŒλ‹€μ˜ νŒŒλΌλ―Έν„° ν˜•μ‹μ„ μΆ”λ‘ ν•˜κΈ° λ•Œλ¬Έμ— 더 쀄일 수 μžˆλ‹€.
inventory.sort((a1 , a2) ->> a1.getWeight().compareTo(a2.getWeight()));

4단계 : λ©”μ„œλ“œ μ°Έμ‘° μ‚¬μš©

  • java.util.Comparator.comparing을 μ •μ μœΌλ‘œ μž„ν¬νŠΈν–ˆλ‹€κ³  κ°€μ •
  • βœ‹ comparing()
    • ComparatorλŠ” Comparableν‚€λ₯Ό μΆ”μΆœν•΄μ„œ Comparator객체둜 λ§Œλ“œλŠ” Functionν•¨μˆ˜λ₯Ό 인수둜 λ°›λŠ” 정적 λ©”μ„œλ“œ comparing을 ν¬ν•¨ν•œλ‹€.
    • 이 λ©”μ„œλ“œκ°€ 정적 λ©”μ„œλ“œμΈ μ΄μœ λŠ” 9μž₯μ—μ„œ μ„€λͺ…ν•œλ‹€.
Comparator<Apple> c = Comparator.comparing((Apple a) -> a.getWeight());

import static java.util.Comparator.comparing;
inventory.sort(comparing(apple -> a.getWeight()));
  • λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ‚¬μš©ν•˜μ—¬ μ½”λ“œλ₯Ό μ‘°κΈˆλ” κ°„μ†Œν™” ν•˜μž
inventory.sort(comparing(Apple::getWeight));

λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‘°ν•©ν•  수 μžˆλŠ” μœ μš©ν•œ λ©”μ„œλ“œ

  • λͺ‡λͺ‡ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” λ‹€μ–‘ν•œ μœ ν‹Έλ¦¬ν‹° λ©”μ„œλ“œλ₯Ό ν¬ν•¨ν•œλ‹€.
  • κ°„λ‹¨ν•œ μ—¬λŸ¬ 개의 λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‘°ν•©ν•΄μ„œ λ³΅μž‘ν•œ λžŒλ‹€ ν‘œν˜„μ‹μ„ λ§Œλ“€ 수 μžˆλ‹€.
    • 두 Predicateλ₯Ό μ‘°ν•©ν•΄μ„œ μ»€λ‹€λž€ Predicateλ₯Ό λ§Œλ“€κ±°λ‚˜,
    • ν•œ ν•¨μˆ˜μ˜ κ²°κ³Όκ°€ λ‹€λ₯Έ ν•¨μˆ˜μ˜ μž…λ ₯이 λ˜λ„λ‘ 두 Function을 μ‘°ν•©ν•  수 μžˆλ‹€.
  • 이와 같은 κΈ°λŠ₯을 κ°€λŠ₯μΌ€ ν•˜λŠ”κ²ƒμ€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ— μ„ μ–Έλœ λ””ν΄νŠΈ λ©”μ„œλ“œμ΄λ‹€. (9μž₯μ—μ„œ μžμ„Ένžˆ μ„€λͺ…)
  • λ””ν΄νŠΈ λ©”μ„œλ“œκ°€ μ–΄λ–€ λ©”μ„œλ“œμΈμ§€λ§Œ μ΄ν•΄ν•˜μž.

Comparator μ‘°ν•©

  • 이전에도 λ³΄μ•˜λ“―μ΄ , 정적 λ©”μ„œλ“œ Comparator.comparing을 μ΄μš©ν•΄μ„œ 비ꡐ에 μ‚¬μš©ν•  ν‚€λ₯Ό μΆ”μΆœ ν•˜λŠ” Function 기반의 Comparatorλ₯Ό λ°˜ν™˜ν•  수 μžˆλ‹€.
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
    Function<? super T, ? extends U> keyExtractor)
{
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}

Comparator<Apple> c = Comparator.comparing((Apple a) -> a.getWeight());

μ—­μ •λ ¬

  • μ‚¬κ³Όμ˜ 무게λ₯Ό λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ μ •λ ¬ν•˜κ³  μ‹Άλ‹€λ©΄? λ‹€λ₯Έ ComparatorμΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€ ν•„μš”κ°€ μ—†λ‹€.
  • μΈν„°νŽ˜μ΄μŠ€ μžμ²΄μ—μ„œ reversedλΌλŠ” λ””ν΄νŠΈ λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.
inventory.sort(comparing(Apple::getWeight).reversed());

Comparatorμ—°κ²°

  • λ¬΄κ²Œκ°€ 같은 μ‚¬κ³ΌλŠ” μ–΄λ–»κ²Œ μ •λ ¬ ν•΄μ•Ό ν• κΉŒ?
  • 이럴 땐 비ꡐ κ²°κ³Όλ₯Ό 더 닀듬을 수 μžˆλŠ” 두 번째 Comparatorλ₯Ό λ§Œλ“€ 수 μžˆλ‹€.
  • thenComparingλ©”μ„œλ“œλ‘œ 두 번째 λΉ„κ΅μžλ₯Ό λ§Œλ“€ 수 μžˆλ‹€.
inventory.sort(comparing(Apple::getWeight)
        .reversed()
        .thenComparing(Apple::getCountry));

Predicate μ‘°ν•©

  • negate , and , or 세가지 λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€.

negate

Predicate<Apple> notRedApple = redApple.negate();

and

Predicate<Apple> redAndHeavyApple = redApple.and(apple -> apple.getWeight > 150);

or

Predicate<Apple> redAndHeavyAppleOrGreen = 
        redApple.and(apple -> apple.getWeight > 150)
                .or(apple -> GREEN.equals(apple.getColor()));

Function μ‘°ν•©

  • Function μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜λŠ” andThen , compose 두 가지 λ””ν΄νŠΈ λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€.

andThen

Function<Integer , Integer> f = x -> x + 1;
Function<Integer , Integer> g = x -> x * 2;
Function<Integer , Integer> h = f.andThen(g);

int result = h.apply(1);
// g(f(x))
// 4λ₯Ό λ°˜ν™˜

compose

Function<Integer , Integer> f = x -> x + 1;
Function<Integer , Integer> g = x -> x * 2;
Function<Integer , Integer> h = f.compose(g);

int result = h.apply(1);
// f(g(x))
// 3을 λ°˜ν™˜
  • μœ ν‹Έλ¦¬ν‹° λ©”μ„œλ“œλ₯Ό μ‘°ν•©ν•΄μ„œ λ‹€μ–‘ν•œ λ³€ν™˜ νŒŒμ΄ν”„ 라인을 λ§Œλ“€ 수 μžˆλ‹€.
Function<String , String> addHeader = Letter::addHeader;
Function<String , String> transformationPipeline = 
    addHeader.andThen(Letter::checkSpelling)
            .andThen(Letter::addFooter);

마치며

λͺ¨λ“  읡λͺ… 클래슀λ₯Ό λžŒλ‹€ ν‘œν˜„μ‹μœΌλ‘œ λ³€ν™˜ν•  수 μžˆλŠ” 것은 μ•„λ‹ˆλ‹€.

  1. 읡λͺ… ν΄λž˜μŠ€μ—μ„œ μ‚¬μš©ν•œ this와 superλŠ” λžŒλ‹€ ν‘œν˜„μ‹μ—μ„œ λ‹€λ₯Έ 의미λ₯Ό κ°–λŠ”λ‹€. 읡λͺ… ν΄λž˜μŠ€μ—μ„œ thisλŠ” 읡λͺ… 클래슀 μžμ‹ μ„ κ°€λ¦¬ν‚€μ§€λ§Œ λžŒλ‹€μ—μ„œ thisλŠ” λžŒλ‹€λ₯Ό κ°μ‹ΈλŠ” 클래슀λ₯Ό 가리킨닀.
  2. 읡λͺ… ν΄λž˜μŠ€λŠ” 감싸고 μžˆλŠ” 클래슀의 λ³€μˆ˜λ₯Ό 가리킬 수 μžˆλ‹€. (μ„€λ„μš° λ³€μˆ˜)
int a = 100;
Runnable r1 = () -> {
    int a = 10; // 컴파일 μ—λŸ¬
    System.out.println(a);
};

Runnable r2 = new Runnable() {
    @Override
    public void run() {
        int a = 10;
        System.out.println(a);
    }
};
  • λžŒλ‹€ ν‘œν˜„μ‹μ€ 읡λͺ… ν•¨μˆ˜μ˜ 일쒅이닀.
    • 이름은 μ—†μ§€λ§Œ , νŒŒλΌλ―Έν„° 리슀트 , λ°”λ”” , λ°˜ν™˜ ν˜•μ‹μ„ 가지며 μ˜ˆμ™Έλ₯Ό 던질 수 μžˆλ‹€.
  • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” ν•˜λ‚˜μ˜ 좔상 λ©”μ„œλ“œλ§Œμ„ μ •μ˜ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ‹€.
    • ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό κΈ°λŒ€ν•˜λŠ” κ³³μ—μ„œλ§Œ λžŒλ‹€ ν‘œν˜„μ‹μ„ μ‚¬μš©ν•  수 μžˆλ‹€.
  • λžŒλ‹€ ν‘œν˜„μ‹μ„ μ΄μš©ν•΄μ„œ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œλ₯Ό μ¦‰μ„μœΌλ‘œ μ œκ³΅ν•  수 있으며 λžŒλ‹€ ν‘œν˜„μ‹ 전체가 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ‘œ μ·¨κΈ‰λœλ‹€.
  • μžλ°” 8은 μ œλ„€λ¦­ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ™€ κ΄€λ ¨ν•œ λ°•μ‹± λ™μž‘μ„ ν”Όν•  수 μžˆλŠ” κΈ°λ³Έν˜• νŠΉν™” μΈν„°νŽ˜μ΄μŠ€κ°€ μ œκ³΅λœλ‹€.
  • μ‹€ν–‰ μ–΄λΌμš΄λ“œ νŒ¨ν„΄ *(μžμ›μ˜ ν• λ‹Ή , μžμ› 정리 λ“± μ½”λ“œ 쀑간에 μ‹€ν–‰ν•΄μ•Ό ν•˜λŠ” λ©”μ„œλ“œμ— κΌ­ ν•„μš”ν•œ μ½”λ“œ)*을 λžŒλ‹€μ™€ ν™œμš©ν•˜λ©΄ μœ μ—°μ„±κ³Ό μž¬μ‚¬μš©μ„±μ„ 얻을 수 μžˆλ‹€.
  • λžŒλ‹€ ν‘œν˜„μ‹μ˜ κΈ°λŒ€ ν˜•μ‹μ„ λŒ€μƒ ν˜•μ‹ 이라고 ν•œλ‹€.
  • λ©”μ„œλ“œ μ°Έμ‘°λ₯Ό μ΄μš©ν•˜λ©΄ 기쑴의 λ©”μ„œλ“œ κ΅¬ν˜„μ„ μž¬μ‚¬μš©ν•˜κ³  직접 전달할 수 μžˆλ‹€.
  • μžλ°”μ—μ„œ μ œκ³΅λ˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ„œλ“œλ“€μ€ 체크 μ˜ˆμ™Έλ₯Ό throwsν•˜κ³  μžˆμ§€ μ•ŠκΈ° λ•Œλ¬Έμ— 직접 throwsλ₯Ό ν•˜λŠ” 좔상 λ©”μ„œλ“œλ₯Ό 가진 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ„ μ–Έν•˜λ˜μ§€, λžŒλ‹€ κ΅¬ν˜„μ—μ„œ try/catchλ₯Ό μ„ μ–Έν•΄μ€˜μ•Ό ν•œλ‹€.