Language/Java

☕ 람닀 표현식(Lambda Expression) 완벜 정늬

읞파_ 2023. 3. 27. 09:09

java-lambda-function

 

람닀 표현식 (Lambda Expression)

람닀 표현식(lambda expression)읎란 핚수형 프로귞래밍을 구성하Ʞ 위한 핚수식읎며, 간닚히 말핮 자바의 메소드륌 간결한 핚수 식윌로 표현한 것읎닀.

지ꞈ까지 자바에서는 메서드륌 하나 표현하렀멎 큎래슀륌 정의핎알 했닀. 하지만 람닀식윌로 표현하멎 메서드의 읎늄곌 반환값을 생략할 수 있고 읎륌 변수에 넣얎 자바 윔드가 맀우 간결핎지는 장점읎 있닀.

아래 귞늌에서 볎듯읎 int add(int a, int b) {} 메소드 표현식을, 메서드 타입, 메서드 읎늄, 맀개변수 타입, 쀑ꎄ혞, return 묞을 생략하고, 화삎표 Ʞ혞륌 넣음윌로썚 윔드륌 혁명적윌로 핚축했음을 볌 수 있닀. 읎러한 특징윌로 람닀식을 읎늄읎 없는 핚수 익명 핚수(anonymous function) ëŒê³ ë„ 한닀.

java-lambda-function

int add(int x, int y) {
    return x + y;
}

// 위의 메서드륌 람닀 표현식을 읎용핎 아래와 같읎 닚축 시킬수 있닀. (메서드 반환 타입, 메서드 읎늄 생략)
(int x, int y) -> {
	return x + y;
};

// 맀개변수 타입도 생략 할 수 있닀.
(x, y) -> {
	return x + y;
};

// 핚수에 늬턎묞 한쀄만 있을 겜우 더욱 더 닚축 시킬 수 있닀. (쀑ꎄ혞, return 생략)
(x, y) -> x + y;
타입을 생략을 핮도 컎파음러가 에러륌 띄우지않는 읎유는, 컎파음러 나늄대로 생략된 타입 위치륌 추론하여 동작하게 핎죌Ʞ 때묞읎닀.

람닀식읎 처음에는 생소하게 느껎젞 였히렀 거부감읎 ë“€ 수 있닀. 하지만 묞법읎 혁신적윌로 ê°„ê²°í•Ž 지는 것만큌, 람닀식에 익숙핎지멎 가독성 멎에서 큰 장점을 얻게 된닀. 특히 컬렉션(Collection)의 요소륌 필터링하거나 맀핑하여 원하는 결곌륌 쉜게 얻을 수 있닀.


람닀식곌 자바슀크늜튞 익명 화삎표 핚수

만음 자바륌 ë°°ìš°êž° 앞서 자바슀크늜튞 프로귞래밍을 뚌저 배욎 독자 분듀읎띌멎 자바의 람닀 표현식을 읎핎하는데 있얎 맀우 수월할 것읎닀. 사싀 자바슀크늜튞의 ìµëª… 화삎표 핚수 ìžì²Žê°€ 람닀 핚수 음종읎Ʞ 때묞읎닀. ꎄ혞륌 생략하거나 등 람닀의 Ʞ볞 묞법 첎계도 자바와 자바슀크늬람 둘닀 비슷하닀. 닚지 화삎표 몚양읎 => ì™€ -> ë¡œ 닀륌 뿐읎닀.

람닀식을 자바슀크늜튞 묞법 형태와 자바의 묞법 형태륌 비교하자멎 아래 윔드와 같닀.

const MyFunction = {
    print: function() {}
};

MyFunction.print = (str) => console.log(str);
let myfunc = MyFunction;
myfunc.print("Hello World");
interface MyFunction {
	void print(String str);
}

public class Main {
    public static void main(String[] args) {
        MyFunction myfunc = (str) -> System.out.println(str);
        myfunc.print("Hello World");
    }
}

변수에 핚수륌 닎을때, 자바슀크늜튞는 앜타입 얞얎띌 타입에 ꎀ계없읎 자유롭게 받을 수 있지만, 자바 같은 겜우 강타입 ì–žì–Ž 읎Ʞ 때묞에 반드시 í•šìˆ˜ì— 대한 타입을 선얞하여알 한닀. 하지만 자바에는 8가지 타입(primitive 타입곌 reference 타입) 밖에 없Ʞ 때묞에 핚수 데읎터 자첎륌 닎을수 있을만한 자료형읎 딱히 적합한 것읎 없닀. 귞래서 자바 개발진듀은 읞터페읎슀륌 익명 구현 객첎 타입윌로썚, 핚수륌 í•Žë‹¹ 읞터페읎슀 타입윌로 받을 수 있게 섀계한 것읎닀.


람닀식곌 핚수형 읞터페읎슀

람닀식의 형태륌 볎멎 마치 자바의 메소드륌 변수로 선얞하는 것 처럌 볎읎지만, 사싀 자바는 메소드륌 닚독윌로 ì„ ì–ží•  수는 없닀. 형태만 귞렇게 볎음 뿐읎지 윔드륌 볎멎 람닀 핚수식을 변수에 대입하고 변수에서 메서드륌 혞출핎서 사용하는 것읎 마치 객첎와 닀늄읎 없닀.

MyFunction myfunc = (str) -> System.out.println(str);
myfunc.print("Hello World");

사싀 람닀식도 결국은 객첎읎닀. 정확히 말하멎 읞터페읎슀륌 ìµëª… 큎래슀로 구현한 ìµëª… 구현 객첎륌 짧게 표현한 것 뿐읎닀. 

 

객첎 지향 방식 vs ëžŒë‹€ 표현 방식

읎에 대핎서 êž°ì¡Ž 자바7에서 표현 했던 객첎 지향 방식곌 람닀 표현 방식을 비교핎볎며 읎핎핎볎자.

닀음 IAdd 띌는 읞터페읎슀가 있고 add() ì¶”상 메서드가 있닀. 우늬는 읎 읞터페읎슀륌 구현하여 메서드륌 정의핎 덧셈 Ʞ능을 읎용할 예정읎닀.

Ʞ졎에는 읞터페읎슀륌 큎래슀에 implements 하고 였버띌읎딩하여 사용핎 왔닀.

interface IAdd {
    int add(int x, int y);
}

class Add implements IAdd {
    public int add(int x, int y) {
        return x + y;
    }
}
        
public class Main {
    public static void main(String[] args) {
        // 생 큎래슀로 메소드 사용하Ʞ
        Add a = new Add();
        
        int result1 = a.add(1, 2);
        System.out.println(result1);
    }
}

더 나아가선 한번만 사용하고 버렀질 큎래슀띌멎, 굳읎 번거롭게 큎래슀륌 선얞하지 말고 익명 큎래슀로 음회용 였버띌읎딩 하여 사용하Ʞ도 하였닀.

interface IAdd {
    int add(int x, int y);
}

public class Main {
    public static void main(String[] args) {
        // 익명 큎래슀로 정의핎 사용하Ʞ (음회용)
        Iadd a = new IAdd() {
            public int add(int x, int y) {
                return x + y;
            }
        };
        
        int result2 = a.add(1, 2);
        System.out.println(result2);
    }
}

귞늬고 람닀는 읎 익명큎래슀 윔드 부분을 짧게 표현한 것읎닀.

interface IAdd {
    int add(int x, int y);
}

public class Main {
    public static void main(String[] args) {
        // 람닀 표현식윌로 핚축 하Ʞ
        IAdd lambda = (x, y) -> { return x + y; }; // 람닀식 끝에 섞믞윜론을 잊지말자
        
        int result3 = lambda.add(1, 2);
        System.out.println(result3);
    }
}

java-lambda-function

람닀식 객첎륌 윘솔에 출력 핎볎멎, 익명 큎래슀 표현 형식곌 또닀륞 ì™žë¶€íŽëž˜ìŠ€ëª…$$Lambda$번혞 ì™€ 같은 ë…자적읞 표현 형식을 지니고 있음을 알 수 있닀.

java-lambda-function

슉, ì•„묎 큎래슀나 추상 큎래슀의 메소드륌 람닀식윌로 쀄읎거나 하는 행위는 못한닀띌는 뜻읎닀. 였로지 읞터페읎슀로 ì„ ì–ží•œ 익명 구현 객첎만읎 람닀식윌로 표현읎 가능하닀. 귞늬고 람닀 표현읎 가능한 읎러한 읞터페읎슀륌 가늬쌜 핚수형 읞터페읎슀띌 쎝칭한닀.

 

핚수형 읞터페읎슀 란?

핚수형 읞터페읎슀란 딱 하나의 추상 메소드가 선얞된 읞터페읎슀륌 말한닀. 위의 IAdd 읞터페읎슀 예제 윔드가 바로 핚수형 읞터페읎슀 읎닀. 귞늬고 람닀식은 핚수형 읞터페읎슀 안에 정의된 하나의 추상 메소드 선얞을 짧게 표현한 것읎닀.

생각핎볎멎 람닀식 자첎가 하나의 메소드륌 한쀄로 정의하는 표현식읎Ʞ 때묞에, 읞터페읎슀에 두개 읎상 추상 메서드가 듀얎있윌멎 읎륌 윔드로 겹쳐 표현할 방법읎 달늬 없Ʞ 때묞에, 였로지 추상 메소드 한개만 가진 읞터페읎슀가 람닀식의 타겟 타입(targe type)읎 될 수 있는 것읎닀.

당, Java 8 버전 부터 읎용읎 가능한 읞터페읎슀의 final 상수나 default, static, private 메서드는 추상 메서드가 아니Ʞ 때묞에, 읎듀 여러개가 읞터페읎슀에 듀얎있얎도 였로지 추상 메서드가 한개읎멎 핚수형 읞터페읎슀로 췚꞉ 된닀.

// 핚수형 읞터페읎슀가 될 수 있닀.
interface IAdd {
    int add(int x, int y);
}

// 핚수형 읞터페읎슀가 될수 없닀.
interface ICalculate {
    int add(int x, int y);
    int min(int x, int y);
}

// 구성요소가 많아도 ê²°êµ­ 추상 메서드는 한개읎Ʞ 때묞에 핚수형 읞터페읎슀읎닀.
interface IAdd {
    int add(int x, int y);

    final boolean isNumber = true; // final 상수
    default void print() {}; // 디폮튾 메서드
    static void print2() {}; // static 메서드
}

 

@FunctionalInterface

나만의 핚수적 읞터페읎슀륌 만듀 때 두 개 읎상의 추상 메소드가 선얞되지 않도록 컎파음러가 checking 핎죌는 Ʞ능읎 있는데, 읞터페읎슀 ì„ ì–ž 시 @FunctionalInterface ì–Žë…ží…ŒìŽì…˜ì„ 붙여죌게 된닀멎 두 개 읎상의 메소드 ì„ ì–ž 시 컎파음 였류륌 발생시쌜쀀닀. 읎는 개발자의 싀수륌 쀄여죌는 역할을 한닀.

@FunctionalInterface
public interface MyFunctional {
    public void method();
    public void otherMethod(); // 컎파음 였류 발생
}

읎밖의 핚수형 읞터페읎슀의 개념 원늬 및 자바에서 제공하는 핚수형 읞터페읎슀 표쀀 API 종류에 대핎서 상섞히 읎핎하고 싶닀멎 닀음 포슀팅을 찞고하Ꞟ 바란닀.

 

☕ 핚수형 읞터페읎슀 표쀀 API 쎝정늬

핚수형 읞터페읎슀 표쀀 API 핚수형 읞터페읎슀(functional interface)는 추상메서드가 1개만 정의된 읞터페읎슀륌 통칭하여 음컫는닀. 읎 읞터페읎슀 형태의 목적은 자바에서 람닀 표현식(Lambda Expressi

inpa.tistory.com


람닀식의 íƒ€ìž… 추론

람닀식윌로 윔드륌 혁신적윌로 쀄음 수 있닀는 점은 알았닀. 귞런데 늬턎 타입도 파띌믞터 타입도 없는 람닀식을 컎파음러가 읎 핚수가 ì–Žë–€ 타입 핚수읞지 알고 묞법을 허용하는 것음까?

사싀 컎파음러 슀슀로 람닀 핚수식을 볎고 추론하여 íƒ€ìž…을 유추하Ʞ 때묞에 가능한 것읎닀. 묎슚 AI 처럌 추론할 정도는 아니고 사람읎 믞늬 정의핎놓은 정의묞을 볎고 추론핎죌는 것읎닀.

java-lambda-function

 

위의 예제는 아죌 ê°„ë‹ší•œ 예제읎고, 대부분의 핚수형 읞터페읎슀륌 읎용하게 되멎 제넀늭(Generics)을 사용하게 되는데, 컎파음러가 타입을 추론하는 데 필요한 타입 정볎 대부분을 제넀늭에서 판별하여 얻는닀고 볎멎 된닀.

닀음 윔드륌 뎐볎자. List 자료형을 만듀고 늬슀튞의 타입 파띌믞터륌 String윌로 지정하였닀. 귞늬고 Collections 큎래슀의 sort ë©”소드륌 불러와 첫번짞 맀개변수로는 늬슀튞 객첎륌 두번짞 맀개변수로는 람닀 핚수륌 전달 하였닀.

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("aaa", "bbb", "ccc", "ddd");

        Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));
    }
}

ì°žê³ ë¡œ 아래의 Collections 큎래슀의 sort 메서드 정의묞을 볎멎, 람닀핚수의 핚수형 읞터페읎슀 타입은 java.util.Comparator ë¡œ 지정되얎 있윌며, 람닀의 맀개변수 타입은 Comparator 읞터페읎슀의 제넀늭 T 타입윌로 지정되얎 있는걞 볌 수 있닀.

java-lambda-function

읎러한 형태에서 컎파음러가 타입을 유추하는 순서는 닀음곌 같읎 된닀.

  1. sort 메소드의 첫번짞 맀개변수로 List<String> 형태의 객첎가 듀얎옚닀.
  2. 첫번짞 맀개변수의 타입 지정에 의핎 sort 메소드의 제넀늭 타입 맀개변수는 몚두 String윌로 지정되게 된닀.
  3. 따띌서 Comparator 읞터페읎슀 제넀늭 타입도 String윌로 지정되며, 추상 메서드의 맀개변수 타입도 String윌로 지정된닀.
  4. 최종적윌로 람닀 핚수의 타입 구성은 int형 메소드 반환 타입곌 String 형 맀개변수 타입 두개로 추론되게 된닀.

java-lambda-function

당, 개발자 입장에선 윔드륌 복Ʞ할때 람닀식의 타입을 위와 같읎 유추하Ʞ에는 시간읎 걞늬Ʞ에, 상황에 따띌 명시적윌로 람닀식 파띌믞터에 타입을 Ʞ재하Ʞ도 한닀. 묎엇읎 좋은지 정답은 없고 상황에 따띌 개발자가 ê²°ì •í•Žì•Œ 한닀.

Collections.sort(words, (String s1, String s2) -> Integer.compare(s1.length(), s2.length()));

람닀 표현식 활용하Ʞ

 

닀양한 람닀식의 할당

람닀식의 가장 큰 특징은 바로 ë³€ìˆ˜ì— 정수륌 할당하듯읎 핚수륌 할당할 수 있닀는 것읎닀.

사싀 핚수도 음반 데읎터 처럌 ë©”몚늬 죌소가 할당 ë˜ì–Ž 있닀. 지ꞈ까지 큎래슀로 메소드륌 사용핎왔Ʞ에 메소드의 메몚늬 죌소륌 변수에 할당하는 음은 없었지만, 람닀식을 읎용하멎 핚수(싀행윔드)의 죌소륌 사용하여 Cì–žì–Ž, 파읎썬 같은 핚수 슀타음의 프로귞래밍을 작성할 수 있게 된 것읎닀.

 

람닀식 변수 할당

interface IAdd {
    int add(int x, int y);
}

public class Main {
    public static void main(String[] args) {
        IAdd lambda = (x, y) -> x + y; // 핚수륌 변수에 할당
        lambda.add(1, 2); // 핚수 사용
    }
}

 

람닀식 맀개변수 할당

특히 람닀식은 ë©”소드의 맀개변수에 바로 입력값윌로 넣는 방식윌로 정말 자죌 애용된닀. 읎것을 핚수륌 메소드의 맀개변수로 넘겚쀀닀고 표현한닀.

interface IAdd {
    int add(int x, int y);
}

public class Main {
    public static void main(String[] args) {
    	int n = result( (x, y) -> x + y ); // 메소드의 맀개변수에 람닀식을 전달
        System.out.println(n); // 3
    }
    
    public static int result(IAdd lambda) {
    	return lambda.add(1,2);
    }
}

Ʞ졎의 자바의 메소드 같은 겜우 변수에 할당하거나 맀개변수로 넣거나 늬턎값윌로 사용하는 행위는 꿈도 못 ꟞얎 왔을 것읎닀. 하지만 람닀식읎 읎런식윌로 응용읎 가능한 읎유는 람닀는 익명 핚수(Anonymous Function)읎며, 익명 핚수는 몚두 ìŒêž‰ 객첎로 췚꞉ 되Ʞ 때묞읎닀.

핚수륌 맀개변수로 전달핎서 사용하는 것을 묎슚 신박한 Ʞ능처럌 소개했지만, 사싀 큎래슀 ì°žì¡° 객첎륌 넘겚 쀀 것곌 닀늄읎 없닀. 왜냐하멎 람닀식은 익명 구현 객첎(익명 큎래슀)륌 심플화 환것읎고, 익명 큎래슀도 ê²°êµ­ 큎래슀 ì°žì¡° 객첎읎니, 우늬가 메소드에 ì°žì¡° 객첎륌 넘겚 메소드 낎에서 객첎의 메서드륌 사용한 것처럌 별반 닀륎지 ì•Šë‹€.

 

람닀식 반환값 할당

음꞉ 객첎의 또닀륞 특징읎띌고 말할수 있는 메서드의 반환값을 ëžŒë‹€í•šìˆ˜ 자첎륌 늬턎하도록 지정 핎쀄 수 있닀. 슉, 메서드의 늬턎값읎 메서드(핚수)읞 것읎닀.

interface IAdd {
    int add(int x, int y);
}

public class Main {
    public static void main(String[] args) {
        IAdd func = makeFunction(); // 메소드의 반환값읎 람닀 핚수
        int result = func.add(1, 2);
        System.out.println(result); // 3
    }

    public static IAdd makeFunction() {
        return (x, y) -> x + y;
    }
}

람닀식 싀전 예제

 

Thread 혞출

자바의 쓰레드륌 뚌저 배우신 독자 분듀읎띌멎, 닀음곌 같은 윔드 묞법 구성에 대핮 익숙할 것읎닀.

읎는 신박한 묞법읎 아니고 결국은 자섞히 볎멎 new Thread() ìƒì„±ìž 안에 맀개변수로서 람닀식을 넣은 것 뿐읎닀.

Thread thread = new Thread( () -> {
    for (int i = 0; i < 10; i++) {
        System.out.println(i);
    }
});

 

enum을 깔끔하게

enum 객첎의 확장을 조ꞈ 더 간결하고 깔끔하게 만듀 수도 있닀.

 

[JAVA] ☕ Enum 엎거형 타입 묞법 & 응용 💯 정늬

Enum ì—Žê±° 타입 뚌저 Enum은 "Enumeration"의 앜자닀. Enumeration은 "ì—Žê±°, 목록, 음람표" 띌는 뜻을 가지고 있윌며, 볎통 한Ꞁ로는 엎거형읎띌고 부륞닀. 슉, 엎거형(enum)은 요소, 멀버띌 불늬는 명명된 값

inpa.tistory.com

enum Operation {
    PLUS("+") { 
        public double apply(double x, double y) { return x + y; }
    },
    MINUS("-") {
        public double apply(double x, double y) { return x - y; }
    },
    TIMES("*") {
        public double apply(double x, double y) { return x * y; }
    },
    DIVIDE("/") {
        public double apply(double x, double y) { return x * y; }
    };
    
    private final String symbol;
   
    Operation(String symbol) { this.symbol = symbol; }
    
    @Override public String toString() { return symbol; } 
    public abstract double apply(double x, double y);
}
import java.util.function.DoubleBinaryOperator;

enum Operation {
    PLUS("+", (x, y) -> x + y),
    MINUS("-", (x, y) -> x - y),
    TIMES("*", (x, y) -> x * y),
    DIVIDE("/", (x, y) -> x / y);

    private final String symbol;
    private final DoubleBinaryOperator op;

    Operation(String symbol, DoubleBinaryOperator op) {
        this.symbol = symbol;
        this.op = op;
    }

    @Override
    public String toString() { return symbol; }

    public double apply(double x, double y) {
        return op.applyAsDouble(x, y);
    }
}

public class Main {
    public static void main(String[] args) {
        // 사용은 아래와 같읎
        Operation.PLUS.apply(2, 3);
    }
}

enum-lambda


람닀식의 형변환

사싀 람닀식은 익명 객첎읎고 타입읎 없닀. 정확히 말하멎 핚수형 읞터페읎슀로 람닀식을 ì°žì¡°í•  수 있을 뿐읎닀. 귞래서 사싀 읞터페읎슀 타입의 변수에 람닀식을 할당하는 행위는 캐슀팅 연산자가 생략 되얎 있닀.

IAdd func = () -> {});

IAdd func = (IAdd) (() -> {}); // 원래는 양변의 타입읎 닀륎므로 형변환읎 필요

읎러한 특징을 읎용핎 람닀식을 몚든 큎래슀의 최상위 큎래슀읞 Object 큎래슀로 형변환읎 가능하닀. 읎러한 특징읎 있닀는 정도만 알고 넘얎가자.

interface IAdd {
    int add(int x, int y);
}

public class Main {
    public static void main(String[] args) {
        IAdd lambda = (x, y) -> x + y;
        System.out.println(lambda);

        // Object 타입윌로 업캐슀팅하Ʞ 위핎선 두번 캐슀팅 핎죌얎알 한닀
        Object lambda_obj = (Object) (IAdd) ((x, y) -> x + y);
        System.out.println(lambda_obj);
    }
}

람닀 표현식의 한계

읎처럌 람닀표현식은 안귞래도 Ꞟ닀란 자바 윔드륌 말끔히 쀄읎는데 상당한 음조륌 하지만, 닚점읎나 사용하Ʞ에 적절치 못한 겜우가 졎재한닀.

 

1. 람닀는 묞서화륌 할 수 없닀

람닀 자첎는 읎늄읎 없는 핚수읎Ʞ 때묞에 메서드나 큎래슀와 닀륎게 묞서화륌 할 수 없닀. 귞래서 윔드 자첎로 동작읎 명확하게 섀명되지 않거나 람닀가 Ꞟ거나 읜Ʞ 얎렵닀멎, 쓰지 않는 방향윌로 늬팩토링하는 것을 고렀핎알 한닀. 

 

2. 람닀는 ë””버깅읎 닀소 까닀롭닀

람닀식은 Ʞ볞적윌로 익명 구현 객첎 Ʞ반읎Ʞ 때묞에, 익명 객첎 특성상 디버깅 할때 윜 슀택(call stack) 추적읎 맀우 얎렀욎 닚점을 가지고 있닀.

예륌듀얎 0을 나누는 같은 였류가 나타나는 윔드륌 음반 for묞곌 람닀식을 읎용한 표현을 윔드륌 싀행하멎 닀음 곌 같읎 에러 쀄 서부터 확연히 닀륞걞 볌 수 있닀.

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

    for (Integer i : list) {
        for (int j = 0; j < i; j++) {
            System.out.println(i / j);
        }
    }
}

java-lambda-cons

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

    list.forEach(i -> {
        IntStream.range(0, i).forEach(j -> {
            System.out.println(i/j);
        });
    });
}

java-lambda-cons

읎는 람닀가 낎부적윌로 수행하는 작업읎 더 많Ʞ 때묞에 발생하는 현상읎Ʞ 때묞에, 윔드가 복잡핎 질수록 얎디에서 묞제가 발생했는지 확읞하Ʞ가 얎렀워지게 된닀. 귞늬고 읎는 곧 성능곌 연결 되Ʞ 도 한닀.

 

3. stream에서 람닀륌 사용할 시 for묞 볎닀 성능읎 떚얎진닀

얎플늬쌀읎션 성능에 맀우 믌감한 사람읎띌멎 치명적읞 닚점읎 될 수 도 있닀.

아래 예제는 0 부터 10000 까지 닚순 순회하는 로직을 stream의 람닀와 닚순 for묞윌로 구성하고 각각 싀행시간을 나녞쎈로 구하는 윔드읎닀. 결곌륌 볎듯읎 두 싀행시간 찚읎는 결윔 적지 ì•Šë‹€.

public static void main(String[] args) {

    // 람닀식 stream 순회 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    long startTime = System.nanoTime(); // 윔드 시작 시간

    IntStream.range(0,10000).forEach((value) -> {});

    long endTime = System.nanoTime(); // 윔드 끝난 시간
    long durationTimeSec = endTime - startTime;
    System.out.println("람닀식 stream 순회 : " + durationTimeSec + "n/s");


    // 음반 for묞 순회 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    startTime = System.nanoTime(); // 윔드 시작 시간

    for(int i=0; i<10000; i++){
    }

    endTime = System.nanoTime(); // 윔드 끝난 시간
    durationTimeSec = endTime - startTime;
    System.out.println("음반 for묞 순회 : " + durationTimeSec + "n/s");
}

java-lambda-cons

 

4. ëžŒë‹€ë¥Œ 낚발하멎 윔드가 지저분핎질 수 있닀

Ʞ졎에는 동작 행위륌 믞늬 큎래슀의 메서드로 정의핎놓고 싀행부에서 ê°–ë‹€ 쓰는 것읎었지만, 람닀는 동작 행위륌 싀행부에서 지정하는 식읎닀. 귞래서읞지 람닀식을 낚발하닀볎멎 비슷하게 생ꞎ 핚수륌 계속 쀑복 생성하고 있는 자신을 발견 할 수 있닀.

interface OperationStrategy {
    // (int x, int y) -> int
    int calculate(int x, int y);
}

// Template
class OperationTemplate {
    int calculate(int x, int y, OperationStrategy cal) {
        int result = cal.calculate(x, y);
        return result;
    }
}
public static void main(String[] args) {
    int x = 100;
    int y = 30;

    OperationContext cxt = new OperationContext();

    int result = cxt.calculate(x, y, (x1, y1) -> x1 + y1);
    System.out.println(result); // 130

    result = cxt.calculate(x, y, (x1, y1) -> x1 - y1);
    System.out.println(result); // 70

    result = cxt.calculate(x, y, (x1, y1) -> x1 * y1);
    System.out.println(result); // 3000

    result = cxt.calculate(x, y, (x1, y1) -> x1 / y1);
    System.out.println(result); // 3
}

비슀묎늬한 람닀 핚수륌 메서드 아규뚌튞로 지정하고 있닀. 위의 예제는 아죌 ê°„ë‹ší•œ 예시띌 와닿지 않을 수 있지만 람닀식 로직읎 두쀄 섞쀄읎 넘얎간닀멎 싀행부의 윔드가 지저분핎 질 수도 있닀.

 

5. ìž¬ê·€ë¡œ 만듀겜우에는 닀소 부적합하닀

람닀식을 통핎 재귀 핚수륌 구축하멎 싀행 ì¡°ì°š 안되는 컎파음 에러가 나타난닀. 

public static void main(String[] args) {

    UnaryOperator<Long> factorial = (x) -> {
        x == 0 ? 1 : x * factorial.apply(x - 1); // compile error
    };

    factorial(1);
}

java-lambda-cons


# 찞고자료

https://github.com/yeGenieee/java-live-study/blob/main/%5B15%5DJava%20Live%20Study.md