λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Java

Java의 λžŒλ‹€ (Lambda)

by young-ji 2022. 10. 31.

βœ… λžŒλ‹€λž€?

μ‹λ³„μž 없이 μ‹€ν–‰ κ°€λŠ₯ν•œ ν•¨μˆ˜.

λžŒλ‹€ ν•¨μˆ˜λŠ” ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μ—μ„œ μ‚¬μš©λ˜λŠ” κ°œλ…μœΌλ‘œ μ΅λͺ… ν•¨μˆ˜λΌκ³ λ„ ν•œλ‹€.

 

Javaμ—μ„œμ˜ λžŒλ‹€

Java8 λΆ€ν„° μ§€μ›λ˜λ©°, λΆˆν•„μš”ν•œ μ½”λ“œλ₯Ό 쀄이고 가독성을 ν–₯μƒμ‹œν‚€λŠ” 것을 λͺ©μ μœΌλ‘œ λ‘κ³ μžˆλ‹€.

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

μžλ°”λŠ” λ©”μ†Œλ“œλ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ 전달할 수 μ—†κΈ° λ•Œλ¬Έμ— 맀번 객체λ₯Ό μƒμ„±ν•΄μ„œ λ§€κ°œλ³€μˆ˜λ‘œ μ „λ‹¬ν•΄μ•Όν•œλ‹€. κ·ΈλŸ¬ν•œ 뢀뢄을 ν•΄κ²°ν•΄μ•Όν•˜λŠ” 것이 λžŒλ‹€ ν‘œν˜„μ‹

public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello");
        }
    }).start();
}


// λžŒλ‹€μ‹ ν‘œν˜„ -> 객체 자체λ₯Ό 직접 생성할 ν•„μš”κ°€ μ—†λ‹€.
// λ©”μ†Œλ“œλ₯Ό μ„ μ–Έν•˜λŠ”κ±° 처럼 λ³΄μ΄μ§€λ§Œ λŸ°νƒ€μž„μ‹œ 읡λͺ… κ΅¬ν˜„ 객체가 μƒμ„±λœλ‹€.
public static void main(String[] args) {
    new Thread(() -> System.out.println("Hello")).start();
}

 

μž₯점

μ½”λ“œμ˜ 라인 μˆ˜κ°€ 쀄어든닀. 가독성을 ν–₯상 μ‹œν‚¨λ‹€.

병렬 ν”„λ‘œκ·Έλž˜λ°μ΄ κ°€λŠ₯ν•˜λ‹€. (λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ μš©μ΄ν•˜λ‹€.)

 

단점

μž¬μ‚¬μš© λΆˆκ°€λŠ₯ν•˜λ‹€.

디버깅이 μ–΄λ ΅λ‹€.

 

 

βœ… λžŒλ‹€μ‹ μ‚¬μš©λ²•

: λ§€κ°œλ³€μˆ˜κ°€ ν•˜λ‚˜μΌ 경우 μƒλž΅ κ°€λŠ₯ 싀행문이 단일일 경우 μ€‘κ΄„ν˜Έ μƒλž΅κ°€λŠ₯

(λ§€κ°œλ³€μˆ˜, ..) -> {μ‹€ν–‰λ¬Έ; ..}

// λ§€κ°œλ³€μˆ˜ νƒ€μž…μ€ λŸ°νƒ€μž„μ‹œμ— λŒ€μž…λ˜λŠ” 값에 따라 μžλ™μœΌλ‘œ μΈμ‹λ˜κΈ° λ•Œλ¬Έμ— 일반적으둜 μƒλž΅ν•œλ‹€.
(a) -> { System.out.println(a); }

// λ§€κ°œλ³€μˆ˜κ°€ ν•˜λ‚˜μΌλ•Œ κ΄„ν˜Έ() μƒλž΅κ°€λŠ₯, 싀행문이 ν•˜λ‚˜λΌλ©΄ μ€‘κ΄„ν˜Έ{} μƒλž΅κ°€λŠ₯
a -> System.out.println(a)

// λ§€κ°œλ³€μˆ˜κ°€ μ—†λ‹€λ©΄ λΉˆκ΄„ν˜Έλ₯Ό λ°˜λ“œμ‹œ μ‚¬μš©ν•΄μ•Όν•œλ‹€.
() -> System.out.println("hello")

// {} λ¦¬ν„΄λ¬Έλ§Œ μžˆμ„ 경우, return 문을 μƒλž΅ν•˜κ³  λ‹€μŒκ³Ό 같이 μ λŠ” 것이 정석이닀.
(x,y) -> { return x+y; }
(x,y) -> x+y;

 

 

 

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

λͺ¨λ“  μΈν„°νŽ˜μ΄μŠ€κ°€ λžŒλ‹€μ‹μ˜ νƒ€κ²Ÿνƒ€μž…μœΌλ‘œ μ‚¬μš©λ  순 μ—†λ‹€.

 

λžŒλ‹€μ‹μ€ ν•˜λ‚˜μ˜ λ©”μ†Œλ“œλ₯Ό μ •μ˜ν•˜κΈ° λ•Œλ¬Έμ— λ‘κ°œ μ΄μƒμ˜ 좔상 λ©”μ†Œλ“œκ°€ μ„ μ–Έλœ μΈν„°νŽ˜μ΄μŠ€λŠ” λžŒλ‹€μ‹μ„ μ΄μš©ν•΄ κ΅¬ν˜„ 객체λ₯Ό 생성할 수 μ—†λ‹€. ν•˜λ‚˜μ˜ 좔상 λ©”μ†Œλ“œκ°€ μ„ μ–Έλœ μΈν„°νŽ˜μ΄μŠ€λ§Œμ΄ λžŒλ‹€μ‹μ˜ νƒ€κ²Ÿ νƒ€μž…μ΄ 될 수 μžˆλŠ”λ°, μ΄λŸ¬ν•œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λΌκ³  ν•œλ‹€.

 

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μž‘μ„±ν• λ•Œ @FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©΄ 두 개 μ΄μƒμ˜ 좔상 λ©”μ†Œλ“œκ°€ 선언될 경우 컴파일 였λ₯˜λ₯Ό λ°œμƒμ‹œμΌœμ€€λ‹€.

 

java 8λΆ€ν„° λΉˆλ²ˆν•˜κ²Œ μ‚¬μš©λ˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” java.util.function ν‘œμ€€ API 둜 μ œκ³΅ν•œλ‹€.

이 νŒ¨ν‚€μ§€μ—μ„œ μ œκ³΅ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ λͺ©μ μ€ λžŒλ‹€μ‹μ„ λŒ€μž…ν•  수 μžˆλ„λ‘ ν•˜κΈ° μœ„ν•΄μ„œμ΄λ©° λ§€κ°œκ°’κ³Ό 리턴값에 따라 크게 Consummer, Supplier, Function, Operator, Predicate둜 κ΅¬λΆ„λœλ‹€.

Consummer<T>  λ§€κ°œκ°’ O, λ¦¬ν„΄κ°’ X  void accept(T t);
Supplier λ§€κ°œκ°’ X, λ¦¬ν„΄κ°’ O  T get();
Function λ§€κ°œκ°’ O, λ¦¬ν„΄κ°’ O R apply(T t)
UnaryOperator λ§€κ°œκ°’ O, λ¦¬ν„΄κ°’ O : μ£Όλ‘œ λ§€κ°œκ°’을 μ—°μ‚°ν•˜κ³  κ²°κ³Όλ₯Ό λ¦¬ν„΄ T apply(T t);
Predicate λ§€κ°œκ°’ O, λ¦¬ν„΄κ°’ boolean : λ§€κ°œκ°’을 μ‘°μ‚¬ν•΄μ„œ true/false λ¦¬ν„΄ boolean test(T t);

 

 

 

βœ… λžŒλ‹€ 캑쳐링 (Variable Capture)

λžŒλ‹€μ— νŒŒλΌλ―Έν„°λ‘œ λ„˜κ²¨μ§„ λ³€μˆ˜κ°€ μ•„λ‹Œ μ™ΈλΆ€μ—μ„œ μ •μ˜λœ λ³€μˆ˜λ₯Ό μžμœ λ³€μˆ˜ν•˜κ³  ν•˜λŠ”λ°, λžŒλ‹€ λ°”λ””μ—μ„œ μžμœ λ³€μˆ˜λ₯Ό μ°Έμ‘°ν• μˆ˜ 있으며 λžŒλ‹€ 캑쳐링이라고 ν•œλ‹€.

둜컬 클래슀, 읡λͺ… ν΄λž˜μŠ€μ—μ„œλ„ μœ μ‚¬ν•˜κ²Œ λ™μž‘ν•œλ‹€.

 

μ§€μ—­λ³€μˆ˜λ₯Ό λžŒλ‹€ 캑처링 ν•  λ•Œ μ œμ•½μ‘°κ±΄μ΄ μ‘΄μž¬ν•œλ‹€.

java 8 이전 β†’ final둜 μ„ μ–Έλ˜μ–΄μ•Ό ν•œλ‹€. μ•ˆκ·ΈλŸΌ 컴파일 μ—λŸ¬ λ°œμƒ

java 8 이후 β†’ final둜 μ„ μ–Έλ˜μ§€ μ•ŠλŠ” 자유 λ³€μˆ˜λŠ” final처럼 λ™μž‘ν•΄μ•Όν•œλ‹€.즉, μ΄ˆκΈ°ν™”λœ 이후 κ°‘μ‹œ ν•œλ²ˆλ„ λ³€κ²½λ˜μ§€ μ•Šμ•„μ•Όν•œλ‹€. (effectively final)

public class LambdaCapturing {
    private int a = 12;

    public void test() {
        final int b = 123;
        int c = 123;
        int d = 123;

        final Runnable r1 = () -> {
            // μΈμŠ€ν„΄μŠ€ λ³€μˆ˜ aλŠ” final둜 μ„ μ–ΈλΌμžˆμ„ ν•„μš”λ„, final처럼 μž¬ν• λ‹Ήν•˜λ©΄ μ•ˆλœλ‹€λŠ” μ œμ•½μ‘°κ±΄λ„ μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€.
            a = 123;
            System.out.println(a);
        };

        // μ§€μ—­λ³€μˆ˜ bλŠ” final둜 μ„ μ–ΈλΌμžˆκΈ° λ•Œλ¬Έμ— OK
        final Runnable r2 = () -> System.out.println(b);

        // μ§€μ—­λ³€μˆ˜ cλŠ” final둜 μ„ μ–ΈλΌμžˆμ§€ μ•Šμ§€λ§Œ final을 μ„ μ–Έν•œ 것과 같이 λ³€μˆ˜μ— 값을 μž¬ν• λ‹Ήν•˜μ§€ μ•Šμ•˜μœΌλ―€λ‘œ OK
        final Runnable r3 = () -> System.out.println(c);
        
        // μ§€μ—­λ³€μˆ˜ dλŠ” final둜 μ„ μ–ΈλΌμžˆμ§€λ„ μ•Šκ³ , κ°’μ˜ μž¬ν• λ‹Ήμ΄ μΌμ–΄λ‚¬μœΌλ―€λ‘œ final처럼 λ™μž‘ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— X
        d = 12;
        final Runnable r4 = () -> System.out.println(d);
    }
}

 

κ·Έ μ΄μœ λŠ” λ¬΄μ—‡μΌκΉŒ?

μ™œ μ΄λŸ¬ν•œ μ œμ•½ 쑰건이 μƒκ²ΌμœΌλ©° μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ—λŠ” 이런 μ œμ•½ 쑰건이 μ—†λŠ” κ²ƒμΌκΉŒ?

κ·Έ μ΄μœ λŠ” JVM λ©”λͺ¨λ¦¬ κ΅¬μ‘°λ•Œλ¬Έ!

JVMμ—μ„œ νž™μ˜μ—­μ— μƒμ„±λ˜λŠ” μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ™€ 달리 지역 λ³€μˆ˜λŠ” μŠ€νƒ μ˜μ—­μ— μƒμ„±λ˜λŠ”λ° μŠ€νƒ μ˜μ—­μ€ μ“°λ ˆλ“œλ§ˆλ‹€ λ³„λ„λ‘œ 생성이 되며 λ”°λΌμ„œ μ“°λ ˆλ“œ 끼리 κ³΅μœ κ°€ λ˜μ§€μ•ŠλŠ”λ‹€.

λžŒλ‹€λŠ” λ³„λ„μ˜ μŠ€λ ˆλ“œμ—μ„œ 싀행이 κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— λžŒλ‹€ 캑쳐링이 λ λ•Œ μ§€μ—­λ³€μˆ˜μ˜ 값을 λ³΅μ‚¬ν•˜μ—¬ μ‚¬μš©(call by value)μ΄λ•Œ λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ 변경이 되면 λ™μ‹œμ„±μ— λŒ€ν•œ μ΄μŠˆκ°€ λ°œμƒν•  수 있기 λ•Œλ¬Έμ΄λ‹€.

 


둜컬 클래슀, 읡λͺ… ν΄λž˜μŠ€μ™€μ˜ 차이

: λžŒλ‹€μ˜ scopeλŠ” 자유 λ³€μˆ˜μ˜ scope와 κ°™κΈ° λ•Œλ¬Έμ— λžŒλ‹€μ—μ„œ 자유 λ³€μˆ˜μ™€ 같은 μ΄λ¦„μ˜ λ³€μˆ˜λ₯Ό μƒμ„±ν•˜λ©΄ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λ‚˜ 둜컬 클래슀, 읡λͺ… ν΄λž˜μŠ€λŠ” 내뢀에 μƒμ„±λœ scopeκ°€ 더 지역적이기 λ•Œλ¬Έμ— 같은 μ΄λ¦„μ˜ λ³€μˆ˜λ₯Ό μ„ μ–Έν•  수 μžˆλ‹€.

public static void main(String[] args) {

    int localNum = 100; // effectively final

	// λžŒλ‹€ error
    IntConsumer consumer = ((localNum) -> System.out.println(localNum));

    // 둜컬 클래슀
    class LocalClass{
        void printNum(){
            int localNum = 101;
            System.out.println(localNum);
        }
    }

    // 읡λͺ… 클래슀
    IntConsumer consumer2 = new IntConsumer(){
        @Override
        public void accept(int localNum){
                System.out.println(localNum);
        }
    }
}

 

 

βœ… λ©”μ†Œλ“œ 레퍼런슀 (Method Reference)

λ©”μ†Œλ“œλ₯Ό κ°„κ²°ν•˜κ²Œ 지칭할 수 μžˆλŠ” λ°©λ²•μœΌλ‘œ λžŒλ‹€κ°€ μ“°μ΄λŠ” κ³³μ—μ„œ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.

이쀑 콜둠 μ—°μ‚°μž(::)라고 ν‘œν˜„ν•˜κΈ°λ„ 함.

 

μ™œ μ‚¬μš©ν• κΉŒ?

λžŒλ‹€μ‹ ν‘œν˜„μ—μ„œ 단 ν•˜λ‚˜μ˜ λ©”μ†Œλ“œλ§Œ ν˜ΈμΆœν•˜λŠ” κ²½μš°μ— ν•΄λ‹Ή λžŒλ‹€μ‹μ—μ„œ λΆˆν•„μš”ν•œ λ§€κ°œλ³€μˆ˜λ₯Ό μ œκ±°ν•˜λŠ” μš©λ„.

λžŒλ‹€μ‹μ— νŒŒλΌλ―Έν„°μ˜ 쀑볡을 ν”Όν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•œλ‹€.

 

1. 정적 λ©”μ†Œλ“œ μ°Έμ‘° (ClassName::StaticMethod)

public class Print {
    public void printNum(int n){
        System.out.println(n);
    }
    public static void printStaticNum(int n){
        System.out.println(n);
    }
}
//Consumer<Integer> printName1 = num -> Print.printStaticNums(num);
Consumer<Integer> printName1 = Print::printStaticNum;

 

2. μΈμŠ€ν„΄μŠ€ λ©”μ†Œλ“œ μ°Έμ‘° (ClassName::MethodName)

Print print = new Print();
//Consumer<Integer> printName1 = num -> print.printNum(num);
Consumer<Integer> printName1 = print::printNum;

 

3. μƒμ„±μž μ°Έμ‘° (ClassName::new)

public class User {
  private String name;

  public User(){}
  public User(String name) {
      this.name = name;
  }
}
// κΈ°λ³Έ μƒμ„±μžλ‘œ 객체 생성
//Supplier<User> userSupplier = () -> new User();
Supplier<User> userSupplier = User::new;
User user1 = userSupplier.get(); //get을 ν•΄μ•Ό μƒμ„±μžλ₯Ό μ΄μš©ν•΄ 객체가 μƒμ„±λœλ‹€.


// μƒμ„±μžλ‘œ 객체 생성
//Function<String,User> userFunction = (name) -> new User(name);
Function<String,User> userFunction = User::new;
User user2 = userFunction.apply("μž₯μ˜μ§€");

3개 μ΄μƒμ˜ 인자λ₯Ό λ°›λŠ” μƒμ„±μžμ˜ μƒμ„±μžλ₯Ό μ°Έμ‘°ν•˜λ €λ©΄ ν˜„μž¬ κ·ΈλŸ¬ν•œ μ‹œκ·Έλ‹ˆμ²˜λ₯Ό κ°–λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ μ œκ³΅λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— 직접 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ§Œλ“€μ–΄μ•Όν•œλ‹€.

 

μž₯단점

κ°„κ²°ν•΄μ§ˆ 수 μžˆλ‹€λŠ” μž₯점이 μžˆμ§€λ§Œ μ΅μˆ™ν•˜μ§€ μ•Šμ€ μ‚¬λžŒμ—κ²ŒλŠ” 였히렀 가독성을 ν•΄μΉ  μš°λ €κ°€ μžˆλ‹€.

 

 

 

 

reference.

https://dev-kani.tistory.com/38

https://itmining.tistory.com/20

https://perfectacle.github.io/2019/06/30/java-8-lambda-capturing/

https://lasbe.tistory.com/75

 


 

Q. [질문] 자유 λ³€μˆ˜κ°€ μ„ μ–Έλœ 후에 λ³€κ²½λ˜λŠ” 것을 μ–΄λ–€ λ°©μ‹μœΌλ‘œ κ°μ§€ν•˜λŠ”μ§€ κΆκΈˆν•©λ‹ˆλ‹€~!

https://www.baeldung.com/java-effectively-final μ»΄νŒŒμΌνƒ€μž„μ— λ„ˆ μˆ˜μ •μž μ—†μœΌλ©΄ 거의 νŒŒμ΄λ„μ΄μ•Ό~ ν•΄μ£ΌλŠ”κ±°κ°™μŠ΅λ‹ˆλ‹€

 

Q. 읡λͺ…ν΄λž˜μŠ€μ—μ„œλŠ” newλ₯Ό μ„ μ–Έν•΄μ„œ μƒˆ 객체λ₯Ό μƒμ„±ν•œλ‹€κ³ ν•΄μ£Όμ…¨λŠ”λ°, λžŒλ‹€λŠ” newκ°€λ˜μ§€μ•ŠλŠ”κ±΄κ°€μš©?

읡λͺ… κ΅¬ν˜„ 객체가 μƒμ„±λ©λ‹ˆλ‹€. μƒˆ 객체가 μƒμ„±λ˜μ§€λ§Œ λ‚΄λΆ€μ μœΌλ‘œ μž¬μ‚¬μš©μ΄λ˜μ–΄ λΉ„μš©μ΄ 더 μ κ²Œλ“ λ‹€κ³  ν•©λ‹ˆλ‹€.

https://sujl95.tistory.com/76

 

Q. μžλ°” 8μ—μ„œ final만 λ˜λŠ”κ²ƒμ—μ„œ Effectively Final도 λ˜λ„λ‘ λ³€κ²½λœ μ΄μœ κ°€ μžˆμ„κΉŒμš”? 무엇인지 κΆκΈˆν•©λ‹ˆλ‹€.

 

 

 

 

잘λͺ»λœ 정보가 μžˆλ‹€λ©΄ λŒ“κΈ€μ„ 톡해 μ•Œλ €μ£Όμ„Έμš”. κ°μ‚¬ν•©λ‹ˆλ‹€. 

'Java' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

[Java] a.equlas(b)λ³΄λ‹€λŠ” Object.equlas(a,b) μ‚¬μš©ν•˜κΈ°  (0) 2022.12.01
JUnit μ‚¬μš©κΈ° (feat. IntelliJ)  (0) 2022.10.26

λŒ“κΈ€