λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
Java·ο»ΏServlet·ο»ΏJSP

[JAVA] λžŒλ‹€μ‹(Lambda Expression)

by Leica 2020. 1. 23.
λ°˜μ‘ν˜•

λžŒλ‹€μ‹(Lambda Expression)

JDK1.8λΆ€ν„° 좔가됨

λžŒλ‹€μ‹μ˜ λ„μž… → μžλ°” = 객체지ν–₯ μ–Έμ–΄ + ν•¨μˆ˜ν˜• μ–Έμ–΄

 

β€» 객체지ν–₯ 언어와 ν•¨μˆ˜ν˜• μ–Έμ–΄λž€?

각각 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ° νŒ¨λŸ¬λ‹€μž„μ„ μ§€μ›ν•˜λŠ” 언어와 ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° νŒ¨λŸ¬λ‹€μž„μ„ μ§€μ›ν•˜λŠ” μ–Έμ–΄

객체지ν–₯ νŒ¨λŸ¬λ‹€μž„
같은 데이터에 λŒ€ν•΄ λ‹€λ₯Έ 처리 절차(데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ” 방식)λ₯Ό μ—¬λŸ¬ 개 λͺ…μ‹œν•΄μ•Ό ν•˜λŠ” κ²½μš°κ°€ 자주 λ°œμƒν•˜λŠ”λ°, 이 λ•Œ κ³΅ν†΅λœ 데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ” 절차λ₯Ό ν•˜λ‚˜λ‘œ λ¬Άμ–΄ 데이터와 μ—¬λŸ¬ 절차λ₯Ό ν•˜λ‚˜μ˜ λ‹¨μœ„λ‘œ λ‹€λ£¨λŠ” νŒ¨λŸ¬λ‹€μž„μ΄λ‹€.

ν•¨μˆ˜ν˜• νŒ¨λŸ¬λ‹€μž„
주어진 데이터λ₯Ό κ°’μœΌλ‘œ κ°„μ£Όν•˜κ³  μƒˆλ‘œμš΄ 값을 μƒμ„±ν•˜λŠ” ν•¨μˆ˜μ— μ΄ˆμ μ„ 맞좀으둜써 λ©”λͺ¨λ¦¬ 관리에 λŒ€ν•œ 뢀담을 μ œκ±°ν•œλ‹€.

 

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

λ©”μ†Œλ“œλ₯Ό ν•˜λ‚˜μ˜ κ°„κ²°ν•œ 식(expression)으둜 ν‘œν˜„ν•œ 것

λ©”μ†Œλ“œλ₯Ό λžŒλ‹€μ‹μœΌλ‘œ ν‘œν˜„ν•˜λ©΄ λ©”μ†Œλ“œμ˜ 이름과 λ°˜ν™˜κ°’μ΄ μ—†μ–΄μ§€λ―€λ‘œ λžŒλ‹€μ‹μ„ '읡λͺ… ν•¨μˆ˜(anonymous function)'라고도 ν•œλ‹€.

 

int[] lambdaArr = new int[5];
Arrays.setAll(lambdaArr, (i) -> (int) (Math.random() * 5) + 1);

μœ„ μ½”λ“œμ—μ„œ ( ) -> (int) (Math.random() * 5) + 1이 λ°”λ‘œ λžŒλ‹€μ‹μ΄λ‹€. 이 λžŒλ‹€μ‹μ΄ ν•˜λŠ” 일을 λ©”μ†Œλ“œλ‘œ ν‘œν˜„ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

 

public static int getRandomNum() {
    return (int) (Math.random() * 5) + 1;
}

μ΄λ ‡κ²Œ λžŒλ‹€μ‹μ€ 클래슀, 객체λ₯Ό μƒμ„±ν•˜κ³  λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  ν•„μš” 없이 λ©”μ†Œλ“œμ˜ 역할을 λŒ€μ‹ ν•  수 μžˆλ‹€.

λ˜ν•œ λžŒλ‹€μ‹μ€ λ©”μ†Œλ“œμ˜ λ§€κ°œλ³€μˆ˜μ™€ λ°˜ν™˜κ°’μ΄ 될 수 μžˆμ–΄ λ©”μ†Œλ“œλ₯Ό λ³€μˆ˜μ²˜λŸΌ λ‹€λ£° 수 있게 ν•œλ‹€.

 

β€» λ©”μ†Œλ“œμ™€ ν•¨μˆ˜

λ©”μ†Œλ“œμ™€ ν•¨μˆ˜λŠ” 같은 μ˜λ―Έμ§€λ§Œ μš©μ–΄λ₯Ό λΆ„λ¦¬ν•΄μ„œ μ‚¬μš©ν–ˆλ‹€. Java의 λ©”μ†Œλ“œλŠ” 객체의 ν–‰μœ„, λ™μž‘μ„ μ˜λ―Έν•˜λ©° νŠΉμ • ν΄λž˜μŠ€μ— λ°˜λ“œμ‹œ 속해야 ν•œλ‹€λŠ” μ œμ•½μ΄ μžˆλ‹€. κ·ΈλŸ¬λ‚˜ JDK1.8 이후 λžŒλ‹€μ‹μ˜ λ„μž…μœΌλ‘œ λ©”μ†Œλ“œκ°€ ν•˜λ‚˜μ˜ 독립적인 κΈ°λŠ₯을 ν•˜κΈ°λ•Œλ¬Έμ— 읡λͺ… ν•¨μˆ˜λΌλŠ” μš©μ–΄λ₯Ό μ‚¬μš©ν•œλ‹€.

 

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

λ©”μ†Œλ“œμ˜ 이름과 λ°˜ν™˜νƒ€μž…μ„ μ œκ±°ν•˜κ³  λ§€κ°œλ³€μˆ˜ 선언뢀와 body{ } 사이에 ->λ₯Ό μΆ”κ°€ν•œλ‹€.

 

ReturnType methodName(Parameter p) {
	// body
}

β–Ό

(Parameter p) -> {
	// body
}

 

# 두 κ°’ μ€‘μ—μ„œ 큰 값을 λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ max()λ₯Ό λžŒλ‹€μ‹μœΌλ‘œ λ³€ν™˜ν•˜κΈ°

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

β–Ό

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

returnλ¬Έ λŒ€μ‹  식(expression)으둜 λŒ€μ‹ ν•  수 μžˆλ‹€. μ‹μ˜ μ—°μ‚° κ²°κ³Όκ°€ μžλ™μœΌλ‘œ λ°˜ν™˜κ°’μ΄ λœλ‹€. λ¬Έμž₯(statement)이 μ•„λ‹ˆλ―€λ‘œ 끝에 μ„Έλ―Έμ½œλ‘ (;)은 뢙이지 μ•ŠλŠ”λ‹€.

β–Ό

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

λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ€ 좔둠이 κ°€λŠ₯ν•œ 경우(λŒ€λΆ€λΆ„μ˜ 경우) μƒλž΅ κ°€λŠ₯ν•˜λ‹€. 참고둜 λ°˜ν™˜νƒ€μž…μ„ μ œκ±°ν•  수 μžˆλŠ” μ΄μœ λ„ 항상 μΆ”λ‘  κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

β–Ό

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

μ΅œμ’… λ³€ν™˜ κ²°κ³Ό

 

3. λžŒλ‹€μ‹ μž‘μ„± 문법 정리

μœ„ μ˜ˆμ—μ„œ μ‚¬μš©λœ μž‘μ„± κ·œμΉ™ 외에도 λͺ‡ 가지 좔가적인 κ·œμΉ™μ΄ μ‘΄μž¬ν•œλ‹€. κ·Έ 문법을 μ •λ¦¬ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

 

1. 기본적인 μž‘μ„± κ·œμΉ™
- 이름과 λ°˜ν™˜νƒ€μž…μ€ μž‘μ„±ν•˜μ§€ μ•ŠλŠ”λ‹€. (anonymous function)

2. λ§€κ°œλ³€μˆ˜
- 좔둠이 κ°€λŠ₯ν•œ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ€ μƒλž΅ν•  수 μžˆλ‹€.
- 단, λ§€κ°œλ³€μˆ˜κ°€ 두 개 이상일 경우 μΌλΆ€μ˜ νƒ€μž…λ§Œ μƒλž΅ν•˜λŠ” 것은 ν—ˆμš©λ˜μ§€ μ•ŠλŠ”λ‹€.
- μ„ μ–Έλœ λ§€κ°œλ³€μˆ˜κ°€ ν•˜λ‚˜μΈ 경우 κ΄„ν˜Έ( )λ₯Ό μƒλž΅ν•  수 μžˆλ‹€.
- 단, λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…μ„ μž‘μ„±ν•œ κ²½μš°μ—” λ§€κ°œλ³€μˆ˜κ°€ ν•˜λ‚˜λΌλ„ κ΄„ν˜Έ( )λ₯Ό μƒλž΅ν•  수 μ—†λ‹€.

3. body { }
- returnλ¬Έ(return statement) λŒ€μ‹  식(expression)으둜 λŒ€μ²΄ν•  수 μžˆλ‹€.
- 식(expression)의 끝에 μ„Έλ―Έμ½œλ‘ (;)은 뢙이지 μ•ŠλŠ”λ‹€.
- κ΄„ν˜Έ{ } μ•ˆμ˜ λ¬Έμž₯이 ν•˜λ‚˜μΌ λ•ŒλŠ” κ΄„ν˜Έ{ }λ₯Ό μƒλž΅ν•  수 μžˆλ‹€.
- 이 λ•Œ, λ¬Έμž₯의 끝에 μ„Έλ―Έμ½œλ‘ (;)은 뢙이지 μ•ŠλŠ”λ‹€.
- κ·ΈλŸ¬λ‚˜ return문은 κ΄„ν˜Έλ₯Ό μƒλž΅ν•  수 μ—†λ‹€.

 

4. λ©”μ†Œλ“œ -> λžŒλ‹€μ‹ λ³€ν™˜ 예제

λ‹€μŒμ€ λ©”μ†Œλ“œλ₯Ό λžŒλ‹€μ‹μœΌλ‘œ λ³€ν™˜ν•œ μ˜ˆμ œμ΄λ‹€.

 

# 예제 1

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

β–Ό

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

 

# 예제 2

void printVar(String name, int i) {
	System.out.println(name + " = " + i);
}

β–Ό

(name, i) -> System.out.println(name + " = " + i)

 

# 예제 3

int square(int x) {
	return x * x;
}

β–Ό

x -> x * x

 

# 예제 4

int roll() {
	return (int) (Math.random() * 6);
}

β–Ό

( ) -> (int) (Math.random() * 6)

 

# 예제 5

int sumArr(int[] arr) {
	int sum = 0;
    for(int i: arr) {
    	sum += i;
    }
    return sum;
}

β–Ό

(int[] arr) -> {
	int sum = 0;
    for(int i: arr) {
    	sum += i;
    return sum;
}

 

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

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λŠ” λžŒλ‹€μ‹μ„ λ‹€λ£¨λŠ” μΈν„°νŽ˜μ΄μŠ€μ΄λ‹€. @FunctionalInterface μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œλ‹€.

λžŒλ‹€μ‹μ€ μ‹€μ œλ‘œλŠ” λ©”μ†Œλ“œ κ·Έ μžμ²΄κ°€ μ•„λ‹ˆλΌ 읡λͺ… 클래슀의 객체와 λ™λ“±ν•˜λ‹€. 읡λͺ… 객체의 λ©”μ†Œλ“œμ™€ λžŒλ‹€μ‹μ˜ λ§€κ°œλ³€μˆ˜, λ°˜ν™˜κ°’μ΄ μΌμΉ˜ν•˜λ©΄ 읡λͺ… 객체λ₯Ό λžŒλ‹€μ‹μœΌλ‘œ λŒ€μ²΄ν•  수 μžˆλ‹€.

 

@FunctionalInterface
interface MyFunction {
	public abstract int max(int a, int b);
}

MyFunction μΈν„°νŽ˜μ΄μŠ€

 

MyFunction μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 읡λͺ… 클래슀의 κ°μ²΄λŠ” μ•„λž˜μ™€ 같이 생성할 수 μžˆλ‹€. (κΈ°μ‘΄ 방식)

MyFunction f = new MyFunction() {	// MyFunction μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 읡λͺ… 클래슀의 객체 생성
					public int max(int a, int b) {
                    	return a > b ? a : b
                    }
                };
int big = f.max(5, 3);	// 읡λͺ… 객체의 λ©”μ†Œλ“œ 호좜

그런데 λžŒλ‹€μ‹μ€ 읡λͺ… 객체와 λ™λ“±ν•˜λ―€λ‘œ μ•„λž˜μ™€ 같이 λŒ€μ²΄ν•  수 μžˆλ‹€.

β–Ό

MyFunction f = (a, b) -> a > b ? a : b;	// 읡λͺ… 객체λ₯Ό λžŒλ‹€μ‹μœΌλ‘œ λŒ€μ²΄
int big = f.max(5, 3);	// 읡λͺ… 객체의 λ©”μ†Œλ“œ 호좜

μ΄λ ‡κ²Œ λžŒλ‹€μ‹μœΌλ‘œ μΈν„°νŽ˜μ΄μŠ€μ˜ μΆ”μƒλ©”μ†Œλ“œλ₯Ό κ΅¬ν˜„ν•  수 있고, λžŒλ‹€μ‹μ„ μ°Έμ‘°λ³€μˆ˜λ‘œ λ‹€λ£° 수 μžˆλ‹€.

 

- ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ—λŠ” λžŒλ‹€μ‹κ³Ό 1:1둜 연결될 수 μžˆλ„λ‘ ν•˜λ‚˜μ˜ 좔상 λ©”μ†Œλ“œλ§Œ μ •μ˜ν•΄μ•Όν•œλ‹€.
- 단, static λ©”μ†Œλ“œμ™€ default λ©”μ†Œλ“œμ˜ κ°œμˆ˜μ—λŠ” μ œμ•½μ΄ μ—†λ‹€.

 

β€» λžŒλ‹€μ‹ Comparator μΈν„°νŽ˜μ΄μŠ€ compare() κ΅¬ν˜„ 예제

List<String> list = Arrays.asList("abc", "aaa", "bbb", "ddd", "aaa");
Collections.sort(list, new Comparator<String>() {
	public int compare(String s1, String s2) {
    	return s2.compareTo(s1);
    }
});

β–Ό

List<String> list = Arrays.asList("abc", "aaa", "bbb", "ddd", "aaa");
Collections.sort(list, (s1, s2) -> s2.compareTo(s1));

 

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

λ©”μ†Œλ“œμ˜ λ§€κ°œλ³€μˆ˜λ₯Ό ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μœΌλ‘œ μ„ μ–Έν•¨μœΌλ‘œμ¨

1. λžŒλ‹€μ‹μ„ μ°Έμ‘°ν•˜λŠ” μ°Έμ‘°λ³€μˆ˜λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ μ§€μ •ν•˜κ±°λ‚˜

2. λžŒλ‹€μ‹μ„ 직접 λ§€κ°œλ³€μˆ˜λ‘œ 지정할 수 μžˆλ‹€.

 

@FunctionalInterface
interface MyFunction {
	void myMethod();
}

class Main {
	static void aMethod(MyFunction f) {	// ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ˜ λ§€κ°œλ³€μˆ˜
    	f.myMethod();
    }
    
    public static void main(String[] args) {
    	MyFunction f = ( ) -> System.out.println("myMethod()");
        aMethod(f);	// λ§€κ°œλ³€μˆ˜ 지정 방법1 - μ°Έμ‘°λ³€μˆ˜ 지정
        aMethod(( ) -> System.out.println("myMethod()"));	// λ§€κ°œλ³€μˆ˜ 지정 방법2 - λžŒλ‹€μ‹ 직접 지정
    }
}

 

λ©”μ†Œλ“œμ˜ λ¦¬ν„΄νƒ€μž…μ„ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μœΌλ‘œ μ§€μ •ν•¨μœΌλ‘œμ¨

1. ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ 좔상 λ©”μ†Œλ“œμ™€ λ™λ“±ν•œ λžŒλ‹€μ‹μ„ κ°€λ¦¬ν‚€λŠ” μ°Έμ‘°λ³€μˆ˜λ₯Ό λ°˜ν™˜ν•˜κ±°λ‚˜

2. λžŒλ‹€μ‹μ„ 직접 λ°˜ν™˜ν•  수 μžˆλ‹€.

 

MyFunction myMethod() {
	MyFunction f = ( ) -> { };
    return f;
}

MyFunction myMethod() {
    return ( ) -> { };
}

 

μ΄λ ‡κ²Œ λžŒλ‹€μ‹μ„ μ°Έμ‘°λ³€μˆ˜λ‘œ λ‹€λ£°μˆ˜ 있고 λ©”μ†Œλ“œλ₯Ό 톡해 λžŒλ‹€μ‹μ„ 주고받을 수 μžˆλ‹€.

 

# 예제

@FunctionalInterface
interface MyFunction {
    void run();
}

public class LambdaEx1 {
    static void execute(MyFunction f) {
        f.run();
    }

    static MyFunction getMyFunction() {
        MyFunction f = () -> System.out.println("f3.run()");
        return f;
    }

    public static void main(String[] args) {
        // 1. 읡λͺ… 클래슀둜 MyFunction.run() κ΅¬ν˜„(κΈ°μ‘΄ 방식)
        MyFunction f1 = new MyFunction() {
            @Override
            public void run() {
                System.out.println("f2.run()");
            }
        };

        // 2. λžŒλ‹€μ‹μœΌλ‘œ MyFunction.run() κ΅¬ν˜„
        MyFunction f2 = () -> System.out.println("f1.run()");

        // 3. λžŒλ‹€μ‹μ„ λ°˜ν™˜ν•˜λŠ” λ©”μ†Œλ“œ 호좜
        MyFunction f3 = getMyFunction();

        f1.run();
        f2.run();
        f3.run();

        execute(f2);    // 1. λžŒλ‹€μ‹μ„ μ°Έμ‘°ν•˜λŠ” μ°Έμ‘°λ³€μˆ˜λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ 지정
        execute(() -> System.out.println("run()")); // 2. λžŒλ‹€μ‹μ„ 직접 λ§€κ°œλ³€μˆ˜λ‘œ 지정
    }
}

 

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

λžŒλ‹€μ‹μ€ 읡λͺ… 객체이고 읡λͺ… κ°μ²΄λŠ” νƒ€μž…μ΄ μ—†λ‹€.(μ •ν™•νžˆλŠ” μ»΄νŒŒμΌλŸ¬κ°€ μž„μ˜λ‘œ 이름을 μ •ν•˜κΈ°λ•Œλ¬Έμ— μ•Œ 수 μ—†λ‹€.) ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ νƒ€μž… μ°Έμ‘°λ³€μˆ˜λ‘œ λžŒλ‹€μ‹μ„ μ°Έμ‘°ν•  수 μžˆλŠ” 것일 뿐, λžŒλ‹€μ‹μ˜ νƒ€μž…μ΄ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€μ˜ νƒ€μž…κ³Ό μΌμΉ˜ν•˜λŠ” 것은 μ•„λ‹ˆλ‹€.

 

MyFunction f = (MyFunction) (() -> {});

κ·Έλž˜μ„œ μ›λž˜λŠ” μœ„μ™€ 같이 ν˜•λ³€ν™˜μ΄ ν•„μš”ν•œλ°, μ΄λŠ” μƒλž΅μ΄ κ°€λŠ₯ν•˜λ‹€. λžŒλ‹€μ‹μ΄ MyFunction μΈν„°νŽ˜μ΄μŠ€λ₯Ό 직접 κ΅¬ν˜„ν•˜μ§€ μ•Šμ§€λ§Œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 클래슀의 객체와 μ™„μ „νžˆ λ™μΌν•˜κΈ° λ•Œλ¬Έμ— μ΄λŸ¬ν•œ ν˜•λ³€ν™˜μ„ ν—ˆμš”μ•ˆλ‹€.

 

λžŒλ‹€μ‹μ€ Object νƒ€μž…μœΌλ‘œ ν˜•λ³€ν™˜ν•  수 μ—†λ‹€. ꡳ이 ν•˜λ €λ©΄ λ¨Όμ € ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‘œ λ³€ν™˜ν•΄μ•Ό ν•œλ‹€.

 

Object obj = (Object) (()->{});	// μ—λŸ¬
Object obj = (Object) (MyFunction) (()->{});	// κ°€λŠ₯
String str = ((Object) (MyFunction) (()->{})).toString();	// κ°€λŠ₯

 

# 예제

@FunctionalInterface
interface MyFunction {
    void myMethod();
}

public class LambdaEx2 {
    public static void main(String[] args) {
        // MyFunction f = (MyFunction) (()->{});
        MyFunction f = ()->{};

        // Object obj = (Object) (MyFunction) (()->{});와 동일. (Object) μƒλž΅
        Object obj = (MyFunction) (()->{});

        // String str = ((Object) (MyFunction) (()->{})).toString();와 동일
        String str = ((MyFunction) (()->{})).toString();

        System.out.println(f);
        System.out.println(obj);
        System.out.println(str);

        // μ—λŸ¬. λžŒλ‹€μ‹μ€ Object νƒ€μž…μœΌλ‘œ ν˜•λ³€ν™˜ μ•ˆλ¨
//        System.out.println(()->{});

        // OK
        System.out.println((MyFunction) (()->{}));

        // μ—λŸ¬
//        System.out.println((MyFunction) (()->{}).toString());

        // OK
        System.out.println(((MyFunction) (()->{})).toString());
    }
}
μ‹€ν–‰ κ²°κ³Ό
com.atoz_develop.LambdaEx2$$Lambda$14/0x0000000100066840@6e8dacdf com.atoz_develop.LambdaEx2$$Lambda$15/0x0000000100066c40@7a79be86 com.atoz_develop.LambdaEx2$$Lambda$16/0x0000000100066040@1e643faf com.atoz_develop.LambdaEx2$$Lambda$17/0x0000000100066440@b684286 com.atoz_develop.LambdaEx2$$Lambda$18/0x0000000100065840@3f3afe78

λžŒλ‹€μ‹μ˜ νƒ€μž…μ€ 일반적인 읡λͺ… 객체와 달리 'μ™ΈλΆ€ν΄λž˜μŠ€μ΄λ¦„$$Lambda$번호'와 같은 ν˜•μ‹μœΌλ‘œ κ²°μ •λœλ‹€.

 

7. λžŒλ‹€μ‹μ˜ μ™ΈλΆ€ λ³€μˆ˜ μ°Έμ‘°

@FunctionalInterface
interface MyFunction {
    void myMethod();
}

class Outer {
    int val = 10;   // Outer.this.val

    class Inner {
        int val = 20;   // this.val

        void method(int i) {    // void method(final int i)
            int val = 30;   // final int val = 30;
            // i = 10;  // final κ°’ λ³€κ²½ λΆˆκ°€

            MyFunction f = () -> {
                System.out.println("i: " + i);
                System.out.println("val: " + val);
                System.out.println("this.val: " + ++this.val);  // μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λŠ” μƒμˆ˜λ‘œ κ°„μ£Όλ˜μ§€ μ•ŠμœΌλ―€λ‘œ λ³€κ²½ κ°€λŠ₯
                System.out.println("Outer.this.val: " + ++Outer.this.val);  // μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λŠ” μƒμˆ˜λ‘œ κ°„μ£Όλ˜μ§€ μ•ŠμœΌλ―€λ‘œ λ³€κ²½ κ°€λŠ₯
            };

            f.myMethod();
        }
    }
}
public class LambdaEx3 {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.method(100);
    }
}
μ‹€ν–‰ κ²°κ³Ό
i: 100
val: 30
this.val: 21
Outer.this.val: 11

이 μ˜ˆμ œλŠ” λžŒλ‹€μ‹ λ‚΄μ—μ„œ 외뢀에 μ„ μ–Έλœ λ³€μˆ˜μ— μ ‘κ·Όν•˜λŠ” 방법을 보여쀀닀. λžŒλ‹€μ‹ λ‚΄μ—μ„œ μ°Έμ‘°ν•˜λŠ” μ§€μ—­λ³€μˆ˜λŠ” final이 뢙지 μ•Šμ•˜μ–΄λ„ μƒμˆ˜(final)둜 κ°„μ£Όλœλ‹€. λžŒλ‹€μ‹ λ‚΄μ—μ„œ μ§€μ—­λ³€μˆ˜ i와 val을 μ°Έμ‘°ν•˜κ³  μžˆμœΌλ―€λ‘œ λžŒλ‹€μ‹ λ‚΄μ—μ„œλ‚˜ λ‹€λ₯Έ μ–΄λŠκ³³μ—μ„œλ„ 이 λ³€μˆ˜λ“€μ˜ 값을 λ³€κ²½ν•  수 μ—†λ‹€.

 

반면 Innerν΄λž˜μŠ€μ™€ Outer클래슀의 μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μΈ this.valκ³Ό Outer.this.val은 μƒμˆ˜λ‘œ κ°„μ£Όλ˜μ§€ μ•ŠμœΌλ―€λ‘œ 값을 λ³€κ²½ν•  수 μžˆλ‹€.

 

void method(int i) {
    int val = 30;

    MyFunction f = (i) -> {	// μ—λŸ¬: μ™ΈλΆ€ μ§€μ—­λ³€μˆ˜μ™€ 이름 쀑볡
        System.out.println("i: " + i);
        System.out.println("val: " + val);
        System.out.println("this.val: " + ++this.val);
        System.out.println("Outer.this.val: " + ++Outer.this.val);
    };

    f.myMethod();
}

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

 

8. java.util.function νŒ¨ν‚€μ§€

java.util.function νŒ¨ν‚€μ§€μ— 자주 μ“°μ΄λŠ” ν˜•μ‹μ˜ λ©”μ„œλ“œκ°€ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ‘œ 미리 μ •μ˜λ˜μ–΄ μžˆλ‹€. 맀번 μƒˆλ‘œμš΄ ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•˜λŠ” 것 보닀 이 νŒ¨ν‚€μ§€μ˜ μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν™œμš©ν•˜μž.

 

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ©”μ†Œλ“œ μ„€λͺ…
java.lang.Runnable void run() λ§€κ°œλ³€μˆ˜λ„ μ—†κ³  λ°˜ν™˜κ°’λ„ μ—†μŒ
Supplier T get() λ§€κ°œλ³€μˆ˜λŠ” μ—†κ³  λ°˜ν™˜κ°’λ§Œ 있음
Consumer void accept(T t) λ§€κ°œλ³€μˆ˜λ§Œ 있고 λ°˜ν™˜κ°’μ€ μ—†μŒ
Function R apply(T t) 일반적인 ν•¨μˆ˜.
ν•˜λ‚˜μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„μ„œ κ²°κ³Όλ₯Ό λ°˜ν™˜
Predicate boolean test(T t) 쑰건식 ν‘œν˜„μ— μ‚¬μš©
λ§€κ°œλ³€μˆ˜λŠ” ν•˜λ‚˜, λ°˜ν™˜ νƒ€μž…μ€ boolean

ν‘œ - μ£Όμš” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

 

# μ‘°κ±΄μ‹μ˜ ν‘œν˜„μ— μ‚¬μš©λ˜λŠ” Predicate

PredicateλŠ” Function의 λ³€ν˜•μœΌλ‘œ λ°˜ν™˜νƒ€μž…μ΄ booleanμ΄λΌλŠ” κ²ƒλ§Œ λ‹€λ₯΄λ‹€. 쑰건식을 λžŒλ‹€μ‹μœΌλ‘œ ν‘œν˜„ν•˜λŠ”λ° μ‚¬μš©λœλ‹€.

 

Predicate<String> isEmptyStr = s -> s.length() == 0;
String s = "";

if(isEmptyStr.test(s)) {
	System.out.println("This is an empty String");
}

 

# λ§€κ°œλ³€μˆ˜κ°€ 두 개인 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ©”μ†Œλ“œ μ„€λͺ…
BiConsumer<T, U> void accept(T t, U u) 두 개의 λ§€κ°œλ³€μˆ˜λ§Œ 있고 λ°˜ν™˜κ°’ μ—†μŒ
BiPredicate<T, U> boolean test(T t, U u) 쑰건식 ν‘œν˜„μ— μ‚¬μš©
λ§€κ°œλ³€μˆ˜ λ‘˜, λ°˜ν™˜κ°’μ€ boolean
BiFunction<T, U, R> R apply<T t, U u> 두 개의 λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„μ„œ ν•˜λ‚˜μ˜ κ²°κ³Όλ₯Ό λ°˜ν™˜

 

λ§€κ°œλ³€μˆ˜κ°€ μ„Έ 개 이상인 ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€κ°€ ν•„μš”ν•˜λ©΄ μ•„λž˜μ™€ 같이 직접 λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.

 

@FunctionalInterface
interface TriFunction<T, U, V, R> {
	R apply(T t, U u, V v);
}

μ„Έ 개의 λ§€κ°œλ³€μˆ˜λ₯Ό λ°›μ•„μ„œ ν•˜λ‚˜μ˜ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ 예

 

# UnaryOperator와 BinaryOperator

Function의 또 λ‹€λ₯Έ λ³€ν˜•μœΌλ‘œ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž…κ³Ό λ°˜ν™˜ νƒ€μž…μ΄ μΌμΉ˜ν•œλ‹€.

 

ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ λ©”μ†Œλ“œ μ„€λͺ…
UnaryOperator<T> T apply(T t) Function의 μžμ†
λ§€κ°œλ³€μˆ˜μ™€ λ¦¬ν„΄κ°’μ˜ νƒ€μž…μ΄ κ°™λ‹€.
BinaryOperator<T> T apply(T t, T t) BiFunction의 μžμ†
λ§€κ°œλ³€μˆ˜μ™€ λ¦¬ν„΄κ°’μ˜ νƒ€μž…μ΄ κ°™λ‹€.

 

# μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›κ³Ό ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€

μ»¬λ ‰μ…˜ ν”„λ ˆμž„μ›μ˜ μΈν„°νŽ˜μ΄μŠ€μ— μΆ”κ°€λœ λ””ν΄νŠΈ λ©”μ†Œλ“œ 쀑 μΌλΆ€λŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‚¬μš©ν•œλ‹€.

 

public class LambdaEx4 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for(int i=0; i<10; i++) {
            list.add(i);
        }

        // list의 λͺ¨λ“  μš”μ†Œλ₯Ό 좜λ ₯
        list.forEach(i-> System.out.print(i+","));
        System.out.println();

        // listμ—μ„œ 2 λ˜λŠ” 3의 배수 제거
        list.removeIf(x->x%2==0 || x%3==0);
        System.out.println(list);

        // list의 각 μš”μ†Œμ— 10을 κ³±ν•œλ‹€
        list.replaceAll(i->i*10);
        System.out.println(list);

        Map<String, String> map = new HashMap<>();
        map.put("1", "1");
        map.put("2", "2");
        map.put("3", "3");
        map.put("4", "4");

        // map의 λͺ¨λ“  μš”μ†Œλ₯Ό {k, v}의 ν˜•μ‹μœΌλ‘œ 좜λ ₯ν•œλ‹€.
        map.forEach((k, v)-> System.out.printf("{"+k+","+v+"},"));
        System.out.println();
    }
}
μ‹€ν–‰ κ²°κ³Ό
0,1,2,3,4,5,6,7,8,9,
[1, 5, 7]
[10, 50, 70]
{1,1},{2,2},{3,3},{4,4},
λ°˜μ‘ν˜•

λŒ“κΈ€