Monday
[Java8] 함수형 인터페이스란? 본문
1. 함수형 인터페이스란?
함수형 인터페이스란 "오직 하나의 추상 메소드"를 갖는 인터페이스를 말합니다. 즉, 인터페이스 안에 1개의 추상메소드만 있으면 함수형 인터페이스라고 부를 수 있습니다. 예를 들어, 인터페이스 안에 자바8에 추가된 디폴트 메서드가 있더라도 추상 메소드가 1개면 함수형 인터페이스입니다. 그리고 함수형 인터페이스를 선언 할 때 @FunctionalInterface 어노테이션을 붙여주면 컴파일러가 올바르게 정의되어 있는지 확인해주므로 꼭 붙여주는 게 좋습니다.
// 함수형 인터페이스 예제 1 - 추상 메소드가 1개
public interface Adder{
int add(int a, int b);
}
// 함수형 인터페이스 예제 2 - 디폴트 메소드가 있지만, 추상 메소드가 1개
@FunctionalInterface
public interface Calculator{
int add(int a, int b);
default int sub(int a, int b){
return a-b;
}
}
2. 함수형 인터페이스를 쓰는 이유?
함수형 인터페이스 사용 이유를 설명하기 위해서는 "람다식"을 얘기해야 합니다. 람다식이란 "(파라미터) -> {구현바디}" 꼴로 함수형 인터페이스의 인스턴스로 취급이 가능합니다. 요약하면, 함수형 인터페이스라면(=추상화 메소드 1개를 갖는 인터페이스라면) 람다식으로 인스턴스화 할 수 있고, 이는 코드의 축약을 가져올 수 있습니다. 알기 쉽게 코드를 통해 살펴보겠습니다.
//함수형 인터페이스 정의
@FunctionalInterface
public interface Adder{
int add(int a, int b);
}
//함수형 인터페이스 인스턴스화 예제
public class App
{
public static void main( String[] args )
{
//익명 클래스로 함수형 인터페이스를 인스턴스화
Adder adder1 = new Adder(){
@Override
public int add(int a, int b){
return a+b;
}
};
//람다식으로 함수형 인터페이스를 인스턴스화
Adder adder2 = (a, b) -> a+b;
// 실행 결과가 같다.
System.out.println(adder1.add(1,3));
System.out.println(adder2.add(1,3));
}
}
3. 자바에서 제공하는 함수형 인터페이스
함수형 인터페이스 | 메소드 | 사용 시기 |
Predicate<T> | boolean test(T t) | T 형식 인자 1개를 받아 true, false 타입으로 반환해야하는 경우 |
Consumer<T> | void accept(T t) | T 형식 인자를 받고 반환 없이 어떤 동작을 수행하고 끝낼 경우 |
Supplier<T> | T get() | 인자를 받지 않고 T 형식 객체를 반환 할 때 경우. 예를 들어, () -> new Adder() 처럼 생성자 형식일 때 사용합니다. |
Function<T, R> | R apply(T t) | T 형식 인자를 받아 R 형식을 반환 할 때 경우 |
Comparator<T> | int compare(T o1, T o2) | T 형식 인자를 받아 int 타입을 반환 할 경우 |
Runnable | void run() | 아무런 인자도 받지 않고 반환도 하지 않습니다. 보통 스레드와 사용 |
Callable<V> | V call() | Supplier와 비슷하나, 만들어진 용도가 조금 다릅니다. Callable은 Runnable과 병렬처리에 자주 사용됩니다. |
4. 기본형 특화 인터페이스
지금까지 확인한 함수형 인터페이스를 제네릭 함수형 인터페이스라고 합니다. 예를 들어, Consumer<T> 에서 T 는 제네릭 타입으로 참조형만 사용 가능합니다.
- 참조형 (Reference Type) : Byte, Integer, Object, List
- 기본형 (Primitive Type) : int, double, byte, char
지금까지 학습한 함수형 인터페이스를 사용하기 위해서는 기본형의 경우 참조형으로 변환 후에 사용할 수 있습니다. 이런 변환 과정은 기본형을 감싸는 래퍼를 생성하고 힙에 저장합니다. 즉, 메모리를 더 소비하게 되고 가져올 때도 메모리를 탐색하는 과정이 필요합니다.
- 박싱 (Boxing) : 기본형 -> 참조형 (int -> Integer)
- 언박싱 (Unboxing) : 참조형 -> 기본형 (Integer -> int)
- 오토 박싱(AutoBoxing) : 개발자가 박싱, 언박싱을 신경쓰지 않고 개발할 수 있게 자동을 변환해주는 기능입니다. 예를 들어, List<Integer> list에 list.add(1)이 가능한 이유는 기본형을 참조형으로 오토박싱 해주기 때문입니다.
함수형 인터페이스에서는 이런 오토박싱 동작을 피할 수 있도록 기본형 특화 함수형 인터페이스 를 제공합니다. 일반적으로 특정 형식을 입력으로 받는 함수형 인터페이스 이름 앞에는 IntPredicate, LongPredicate처럼 형식명이 붙습니다.
IntPredicate, LongPredicate 등등 특정 타입만 받는 것이 확실하다면 기본형 특화 인터페이스를 사용하는 것이 더 좋습니다.
'언어 > Java' 카테고리의 다른 글
2. Java 기본 문법(데이터 타입, 변수, 제어문) (0) | 2024.11.10 |
---|---|
1. 실무에서 자주 사용하는 Java 코딩 컨벤션 (0) | 2024.11.10 |
[Java8] Optional 이란? (0) | 2022.04.15 |
[Java8] Stream이란? (0) | 2022.03.13 |
Java8 Unsigned (0) | 2021.08.01 |