Java

FunctionalInterface, Lambda Expression

blackbearwow 2024. 9. 26. 12:41

ArrayList의 forEach, removeIf, sort 메소드 등 많은 곳에서 FunctionalInterface를 매개변수로 받고 있다. FunctionalInterface는 무엇인지 람다식은 무엇인지 알아보자.

FunctionalInterface란?

https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/FunctionalInterface.html 에서 보면, 디폴트 메소드를 제외한 abstract method가 하나인 인터페이스라고 말한다.

 

인터페이스 위에 @FunctionalInterface 어노테이션을 사용하는데, 이 어노테이션을 사용하면 인터페이스가 FunctionalInterface의 조건에 맞는지 컴파일러가 확인해준다. 어노테이션을 붙이지 않아도 동작에 상관이 없지만, 잘못될 경우가 있으니 사용하는 것이 좋다.

 

커스텀 FunctionalInterface 예시)

class Main {
    public static void main(String[] args) {
        Sum s = (a, b) -> (a + b);
        for (int i = 0; i < 10; i++) {
            System.err.println(s.oneMethod(i, 2));
        }
    }

    @FunctionalInterface
    public interface Sum {
        int oneMethod(int a, int b);
    }
}

 

FunctionalInterface는 lambda expression과 method reference의 타깃이다. 그렇다면 lambda expression과 method reference는 무엇인가?

Lambda expression

람다식은 Java8에 추가된 것으로 간단한 코드 블럭이다.

Lambda 문법

() -> {code block}
(parameter1) -> {code block}
(parameter1, parameter2) -> {code block}

() -> expression
(parameter1) -> expression
(parameter1, parameter2) -> expression

parameter1 -> expression
parameter1 -> {code block}

()안에 매개변수를 넣으며, 매개변수가 1개일 경우에만 괄호를 생략할 수 있다. 

중간에 ->가 있다.

{}에 code block을 넣을 수 있다. 괄호를 생략할 경우에는 expression 값이 반환된다. 생략한다면 변수, 할당, 조건문, 반복문을 사용하지 못하며 즉시 값을 반환해야 한다.

lambda expression의 타겟은 FunctionalInterface여야만 한다.

 

예시)

import java.util.ArrayList;

class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arr = new ArrayList<>();
        Sum s = (a, b) -> (a + b);
        for (int i = 0; i < 10; i++) {
            arr.add(s.get(i, 2));
        }
        arr.forEach((n) -> {
            for (int i = 0; i < n; i++)
                System.out.print('*');
            System.err.println();
        });
    }

    @FunctionalInterface
    public interface Sum {
        int get(int a, int b);
    }
}

출력: 

**
***
****
*****
******
*******
********
*********
**********
***********

Method reference

메소드 참조는 메소드를 FunctionalInterface로 반환하는 방법이다. 일반 메소드, static 메소드, 생성자를 참조할 수 있으며 클래스이름::메소드이름 으로 참조한다.

 

이때 FunctionalInterface의 매개변수 타입 == 메소드의 매개변수타입, FunctionalInterface의 매개변수 개수 == 메소드의 매개변수 개수, 함수형 인터페이스의 반환형 == 메소드의 반환형 3가지 조건을 만족시켜야 한다.

 

예시)

import java.util.ArrayList;

class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arr = new ArrayList<>();
        Sum s = (a, b) -> (a + b);
        for (int i = 0; i < 10; i++) {
            arr.add(s.get(i, 2));
        }
        arr.forEach(System.out::println);
    }

    @FunctionalInterface
    public interface Sum {
        int get(int a, int b);
    }
}

출력:

2

3

4

5

6

7

8

9

10

11

java.util.function

JDK에서 사용되는 일반적인 목적의 함수형 인터페이스의 모음 package이다. ArrayList, ArrayDeque, LinkedList 등에서 사용된다.

 

4가지 기본적인 함수형 인터페이스가 있다.

인터페이스 설명
Supplier<T> 매개변수 없이 반환값만 있다
Consumer<T> 단항의 매개변수를 받고 반환값이 없다
Predicate<T> 단항의 매개변수를 받고 Boolean을 반환한다
Function<T, R> 단항의 매개변수를 받아 처리후 R로 반환한다

위 인터페이스 외에 Bi가 붙은 인터페이스(BiConsumer, BiPredicate, BiFunction 등)는 2항의 매개변수를 받는 인터페이스이다.


참고: https://mangkyu.tistory.com/113

https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/FunctionalInterface.html

https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/package-summary.html

https://mangkyu.tistory.com/113

-

'Java' 카테고리의 다른 글

Java annotation  (0) 2024.10.29
Java concurrent programming  (0) 2024.09.27
Java 파일 조작 (File Handling)  (0) 2024.09.23
Java 예외 처리 (Exception, try catch)  (1) 2024.09.21
Java Regular Expressions (정규 표현식)  (0) 2024.09.20