Lambda

์ž๋ฐ”๋Š” ๊ฐ์ฒด์ง€ํ–ฅ์–ธ์–ด์ด์ง€๋งŒ, ์ž๋ฐ” 8์— ๋„์ž…๋œ ๋žŒ๋‹ค์‹์„ ํ†ตํ•ด ํ•จ์ˆ˜ํ˜• ์–ธ์–ด์˜ ํŠน์ง•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋žŒ๋‹ค์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ์‹์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฝ”๋“œ์˜ ์–‘์„ ์ค„์ด๋ฉด์„œ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ ๋žŒ๋‹ค์‹์€ ๋ฉ”์„œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค(Functional Interface)

ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹จ ํ•˜๋‚˜์˜ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งํ•˜๋ฉฐ, ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ํ•จ์ˆ˜๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์ต๋ช… ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

interface MyFunction {

    int max(int a, int b);
}


class Example {

    public static void main(String[] args) {
        MyFunction f = new MyFunction() {
            @Override
            public int max(int a, int b) {
                return a > b ? a : b;
            }
        };
        int value = f.max(3, 5);
    }
}

์œ„ ์ฝ”๋“œ์˜ ๋ฉ”์„œ๋“œ max() ๋ฉ”์„œ๋“œ๋ฅผ ๋žŒ๋‹ค์‹์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

class Example {

    public static void main(String[] args) {
        MyFunction f = (int a, int b) -> a > b ? a : b;
        int value = f.max(3, 5);
    }
}

์ด์ฒ˜๋Ÿผ MyFunction ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์ต๋ช… ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ๋žŒ๋‹ค์‹์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š” ๊ตฌํ˜„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ๋˜๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด์€ default ๋ฉ”์„œ๋“œ๋‚˜ static ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ตฌํ˜„ํ•ด์•ผ ํ•  ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋Š” ํ•˜๋‚˜๋งŒ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค. ๊ฒฐ๊ตญ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ์ถ”์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ ํ•˜๋‹ˆ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋žŒ๋‹ค์‹์„ ํ†ตํ•ด ์ต๋ช… ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

@FunctionalInterface

@FunctionalInterface ์–ด๋…ธํ…Œ์ด์…˜์€ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๊ฐ€ ํ•˜๋‚˜๋งŒ ์กด์žฌํ•˜๋Š”์ง€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ฒดํฌํ•˜๋„๋ก ํ•˜์—ฌ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ •์˜ํ–ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜๋Š” ์‹ค์ œ Comparator ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ •์˜์ด๋‹ค.


@FunctionalInterface
public interface Comparator<T> {

    int compare(T o1, T o2);

    // ...

    default Comparator<T> reversed() {
        // ... ๊ตฌํ˜„ ๋‚ด์šฉ
    }

    // ๊ทธ ์™ธ default / static ๋ฉ”์„œ๋“œ
}

๋ฐ˜ํ™˜๊ณผ ๋งค๊ฐœ๋ณ€์ˆ˜

๋ฉ”์„œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ธ ๊ฒฝ์šฐ ๋žŒ๋‹ค์‹์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

interface MyConsumer {

    void accept(String str);
}

class Example {

    public static void main(String[] args) {
        MyConsumer c = str -> System.out.println(str);
        doSomething(5, c);
    }

    static void doSomething(int n, MyConsumer c) {
        for (int i = 0; i < n; i++) {
            c.accept("Hello" + i);
        }
    }
}

๊ทธ๋ฆฌ๊ณ  ๋ฐ˜ํ™˜ํƒ€์ž…์ด ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค์ธ ๊ฒฝ์šฐ ๋žŒ๋‹ค์‹์œผ๋กœ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.


@FunctionalInterface
interface MyFunction {

    void run();
}

class Example {

    // ๋ฐ˜ํ™˜ ํƒ€์ž…์ด MyFunction์ธ ๋ฉ”์„œ๋“œ
    static MyFunction getMyFunction() {
        MyFunction f = () -> System.out.println("Hello");
        return f;
    }

    public static void main(String[] args) {
        MyFunction f = getMyFunction();

        f.run(); // Hello
    }
}

java.util.function ํŒจํ‚ค์ง€

์ผ๋ฐ˜์ ์œผ๋กœ ์ž์ฃผ ์“ฐ์ด๋Š” ํ˜•์‹์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋“ค์„ ๋ฏธ๋ฆฌ ์ •์˜ํ•ด๋†“์€ ํŒจํ‚ค์ง€๋กœ ์ž์ฃผ ์“ฐ์ด๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

์ธํ„ฐํŽ˜์ด์Šค
๋ฉ”์„œ๋“œ
๋งค๊ฐœ๋ณ€์ˆ˜
๋ฐ˜ํ™˜๊ฐ’

java.lang.Runnable

void run()

์—†์Œ

์—†์Œ

Supplier

T get()

์—†์Œ

T

Consumer

void accept(T t)

T

์—†์Œ

Function<T, R>

R apply(T t)

T

R

Predicate

boolean test(T t)

T

boolean

์œ„ ์ธํ„ฐํŽ˜์ด์Šค ์ค‘ Function<T, R>๊ณผ Predicate<T>๋ฅผ ํ™œ์šฉํ•œ ์˜ˆ์‹œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

class Example {

    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve", "Frank");

        // Predicate: ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๊ฐ€ 4๋ณด๋‹ค ํฐ์ง€ ํ™•์ธ
        Predicate<String> lengthGreaterThan4 = s -> s.length() > 4;

        // Function: ๋ฌธ์ž์—ด์„ ๋Œ€๋ฌธ์ž๋กœ ๋ณ€ํ™˜
        Function<String, String> toUpperCase = s -> s.toUpperCase();

        // ๋ฌธ์ž์—ด ๊ธธ์ด๊ฐ€ 4๋ณด๋‹ค ํฐ ์ด๋ฆ„์„ ํ•„ํ„ฐ๋งํ•˜๊ณ  ๋Œ€๋ฌธ์ž๋กœ ๋ณ€ํ™˜
        List<String> result = names.stream()
                .filter(lengthGreaterThan4)
                .map(toUpperCase)
                .collect(Collectors.toList());

        // ์œ„ ์ฝ”๋“œ๋ฅผ ๋žŒ๋‹ค์‹์œผ๋กœ ํ‘œํ˜„ํ•œ ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
//        List<String> result = names.stream()
//                .filter(s1 -> s1.length() > 4)
//                .map(s -> s.toUpperCase())
//                .collect(Collectors.toList());

        System.out.println(result);
    }
}

๊ทธ ์™ธ์—๋„ BiFunction<T, U, R>๊ณผ BiPredicate<T, U> ๋“ฑ๊ณผ ๊ฐ™์€ ๋‘ ๊ฐœ ์ด์ƒ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋„ ์žˆ์œผ๋ฉฐ, UnaryOperator<T>์™€ BinaryOperator<T>๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๋ฐ˜ํ™˜๊ฐ’์˜ ํƒ€์ž…์ด ๊ฐ™๋Š” ํ•จ์ˆ˜ํ˜• ์ธํ„ฐํŽ˜์ด์Šค๋„ ์กด์žฌํ•œ๋‹ค.

๋ฉ”์„œ๋“œ ์ฐธ์กฐ(Method Reference)

๋ฉ”์„œ๋“œ ์ฐธ์กฐ๋Š” ๋žŒ๋‹ค์‹์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์ต๋ช… ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์ „๋‹ฌ ๋ฐ›์€ ์ธ์ž๋ฅผ ๊ทธ๋Œ€๋กœ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


@FunctionalInterface
interface MyFunction {

    void print(String str);
}

class Example {

    public static void main(String[] args) {
        // ๋žŒ๋‹ค์‹
        MyFunction f1 = (str) -> System.out.println(str);
        // ๋ฉ”์„œ๋“œ ์ฐธ์กฐ
        MyFunction f2 = System.out::println;
        f1.print("Hello World!");
        f2.print("Hello World!");
    }
}

์ฐธ๊ณ ์ž๋ฃŒ

Last updated

Was this helpful?