[ 표준 API의 함수적 인터페이스 ]

자바에서 제공되는 표준 API에서 한 개의 추상 메소드를 가지는 인터페이스들은 모두 람다식을 이용해서 익명 구현 객체로 표현이 가능하다.

예를 들어 스레드의 작업을 정의하는 Runnable 인터페이스는 매개 변수와 리턴값이 없는 run() 메소드만 존재하기 때문에
다음과 같이 람다식을 이용해서 Runnable 인스턴스를 생성시킬 수 있다.

  • RunnableExample (함수적 인터페이스와 람다식)
public class RunnableExample {
    public static void main(String[] args) {
        Runnable runnable = () -> {
            for (int i = 0; i < 10; i++) {  //람다식 (스레드가 실행하는 코드)
                System.out.println(i);
            }
        };

        Thread thread = new Thread(runnable);
        thread.start();
    }
}
  • Thread 생성자를 호출할 때 다음과 같이 람다식을 매개값으로 대입해도 된다.
Thread thread = new Thread(() -> {
    for (int i = 0; i < 10; i++)
        System.out.println(i);
    }
 });
  • 실행 결과
0
1
2
3
4
5
6
7
8
9

자바 8부터는 빈번하게 사용되는 함수적 인터페이스(funcational Interface)는 java.util.function 표준 API 패키지로 제공한다. 이 패키지에서 제공하는 함수적 인터페이스의 목적은 메소드 또는 생성자의 매개 타입으로 사용되어 람다식을 대입할 수 있도록 하기 위해서이다.

자바 8부터 추가되거나 변경된 API에서 이 함수적 인터페이스들은 매개 타입으로 많이 사용한다. 물론 우리가 개발하는 메소드에도 이 함수적 인터페이스들을 매개 타입으로 많이 사용한다.

java.util.function 패키지의 함수적 인터페이스는 크게 Consumer, Supplier, Function, Operator, Predicate로 구분된다. 구분 기준은 인터페이스에 선언된 추상 메소드의 매개값과 리턴값의 유무이다.


1. Consumer 함수적 인터페이스

Consumer 함수적 인터페이스는 리턴값이 없는 accept()를 가지고 있다. accept() 메소드는 단지 매개값을 소비하는 역할만 한다.

  • 여기서 소비한다는 말은 사용만 할 뿐 리턴값이 없다는 뜻이다.
  • 매개 변수의 타입과 수에 따라서 아래와 같은 Consumer들이 있다.

Consumer<T>

  • accept() 메소드는 매개값으로 T 객체 하나를 가지므로 람다식도 한 개의 매개 변수를 사용한다.
  • 타입 파라미터 TString이 대입되었기 때문에 t 매개 변수 타입은 String이 된다.
Consumer<String> consumer = t -> { t를 소비하는 실행문; };

BiConsumer<T, U>

  • accept() 메소드는 매개값으로 TU 두 개의 객체를 가지므로 람다식도 두 개의 매개 변수를 사용한다.
  • 타입 파라미터 TUString이 대입되었기 때문에 람다식의 tu 매개 변수 타입은 각각 String이 된다.
BiConsumer<String, String> consumer = (t, u) -> { t와 u를 소비하는 실행문; }

DoubleConsumer

  • accept() 메소드는 매개값으로 double 하나를 가지므로 람다식도 한 개의 매개 변수를 사용한다.
  • d는 고정적으로 double 타입이 된다.
DoubleConsumer consumer = d -> { d를 소비하는 실행문; }

ObjIntConsumer<T>

  • accept() 메소드는 매개값으로 T 객체와 int 값 두 개를 가지기 때문에 람다식도 두 개의 매개 변수를 사용한다.
  • TString 타입이므로 람다식의 t 매개 변수 타입은 String이 되고, i는 고정적으로 int 타입이 된다.
ObjIntConsumer<String> consumer = (t, i) -> { t와 i를 소비하는 실행문; }

2. Supplier 함수적 인터페이스

Supplier 함수적 인터페이스는 매개 변수가 없고 리턴값이 있는 getXXX() 메소드를 가지고 있다. 이 메소드들은 실행 후 호출한 곳으로 데이터를 리턴(공급)하는 역할을 한다.

리턴 타입에 따라서 아래와 같은 Supplier 함수적 인터페이스들이 있다.


Supplier<T>

  • get() 메소드가 매개값을 가지지 않으므로 람다식도 ()를 사용한다.
  • 람다식의 중괄호 {}는 반드시 한 개의 T 객체를 리턴하도록 해야 한다.
  • TString 타입이므로 람다식의 중괄호 {}는 문자열을 리턴하도록 해야 한다.
Supplier<String> supplier = () -> { ...; return "문자열"; }

IntSupplier

  • getAsInt() 메소드가 매개값을 가지지 않으므로 람다식도 ()을 사용한다.
  • 람다식의 중괄호 {}는 반드시 int 값을 리턴하도록 해야 한다.
IntSupplier supplier = () -> { ...; return int; }

3. Function 함수적 인터페이스

Function 함수적 인터페이스는 매개값과 리턴값이 있는 applyXXX() 메소드를 가지고 있다. 이 메소드들은 매개값을 리턴값으로 매핑(타입 변환)하는 역할을 한다.

매개 변수 타입과 리턴 타입에 따라서 아래와 같은 Function 함수적 인터페이스들이 있다.


Function<T, R> 인터페이스

  • apply() 메소드는 매개값으로 T 객체 하나를 가지므로 람다식도 한 개의 매개 변수를 사용한다.
  • apply() 메소드의 리턴 타입이 R이므로 람다식 중괄호 {}의 리턴값은 R 객체가 된다.
  • TStudent 타입이고 RString 타입이므로 t 매개 변수 타입은 Student가 되고, 람다식의 중괄호 {}String을 리턴해야 한다.
  • t.getName()Student 객체의 getName() 메소드를 호출해서 학생 이름(String)을 얻는다. return 문만 있을 경우 중괄호 {}return 문은 생략할 수 있다.

다음 코드는 Student 객체를 학생 이름(String)으로 매핑하는 것이다.

Function<Student, String> function = t -> { return t.getName(); }
또는
Function<Student, String> function = t -> t.getName();

ToIntFunction<T> 인터페이스

  • applyAsInt() 메소드는 매개값으로 T 객체 하나를 가지므로 람다식도 한 개의 매개 변수를 사용한다.
  • applyAsInt() 메소드의 리턴 타입이 int이므로 람다식 중괄호 {}의 리턴값은 int가 된다.
  • TStudent 타입이므로 t 매개 변수 타입은 Student가 된다.
  • t.getScore()Student 객체의 getScore() 메소드를 호출해서 학생 점수(int)를 얻는다.

다음 코드는 Student 객체를 학생 점수(int)로 매핑하는 것이다.

ToIntFunction<Student> function = t -> { return t.getScore(); }
또는
ToIntFunction<Student> function = t -> t.getScore();

4. Operator 함수적 인터페이스

Operator 함수적 인터페이스는 Function과 동일하게 매개 변수와 리턴값이 있는 applyXXX() 메소드를 가지고 있다. 하지만 이 메소드들은 매개값을 리턴값으로 매핑(타입 변환)하는 역할보다는 매개값을 이용해서 연산을 수행한 후 동일한 타입으로 리턴값을 제공하는 역할을 한다.

매개 변수의 타입과 수에 따라서 아래와 같은 Operator 함수적 인터페이스들이 있다.


IntBinaryOperator 인터페이스

  • applyAsInt() 메소드는 매개값으로 두 개의 int를 가지므로 람다식도 두 개의 int 매개 변수 ab를 사용한다.
  • applyAsInt() 메소드의 리턴 타입이 int이므로 람다식의 중괄호 {}의 리턴값은 int가 된다.

다음 코드는 두 개의 int를 연산해서 결과값으로 int를 리턴한다.

IntBinaryOperator operator = (a, b) -> { ...; return int; }

5. Predicate 함수적 인터페이스

Predicate 함수적 인터페이스는 매개 변수와 boolean 리턴값이 있는 testXXX() 메소드를 가지고 있다. 이 메소드들은 매개값을 조사해서 true 또는 false를 리턴하는 역할을 한다.

매개 변수의 타입과 수에 따라서 아래와 같은 Predicate 함수적 인터페이스들이 있다.


Predicate<T> 인터페이스

  • test() 메소드는 매개값으로 T 객체 하나를 가지므로 람다식도 한 개의 매개 변수를 사용한다.
  • test() 메소드의 리턴 타입이 boolean이므로 람다식 중괄호 {}의 리턴값은 boolean이 된다.
  • TStudent 타입이므로 t 매개 변수 타입은 Student가 된다.
  • t.getSex()Student 객체의 getSex() 메소드를 호출해서 "남자" 또는 "여자"를 얻는다.

결국 다음 코드는 Stringequals() 메소드를 이용해서 남학생만 true를 리턴한다.

Predicate<Student> predicate = t -> { return t.getSex().equals("남자"); }
또는
Predicate<Student> predicate = t -> t.getSex().equals("남자");

[ 참고자료 ]

이것이 자바다 책

profile
🚧 https://coji.tistory.com/ 🏠

0개의 댓글