개요
이름부터 아찔하다. 함수형 인터페이스라니..
최근에 '이펙티브 자바'라는 개발 서적을 읽고 있는데, 그 안에 람다식에 대한 내용이 포함되어 있었다.
그래서 람다식에 대해 공부좀 해볼까 싶어서 살펴보니, 결국 함수형 인터페이스를 기반으로 한다는 것을 알게 되었다.
그래서 오늘 한번 간단히 함수형 인터페이스에 대해 일기를 써보게 되었다.
함수형 인터페이스
함수형 인터페이스란, 단 하나의 추상 메서드만을 가지는 인터페이스를 말한다.
… 생각보다 너무 단순한다.
아래의 코드도 함수형 인터페이스다.
@FunctionalInterface
public interface MyFunction {
// 하나의 추상 메서드
int add(int a, int b);
}
(참고) 추상 메서드
추상 메서드란, 구현부가 작성되지 않은 메서드를 말한다.
다음은 위의 MyFunction 클래스를 사용해 람다식을 작성한 것이다.
public class LambdaExample {
public static void main(String[] args) {
MyFunction addFunction = (a, b) -> a + b;
System.out.println(addFunction.add(5, 3)); // 8
}
}
위 코드에서 함수형 인터페이스의 특징이 들어나는 것이 (a, b) -> a + b; 부분이다.
(a, b) -> a + b;
생긴 것을 보면 메서드에 a와 b를 매개변수로 주입하는 것 같다.
사실 그게 맞다.
그러면 어떤 메서드에 a와 b를 넣는거지..?
그것은 MyFunction 인터페이스의 add() 메서드이다.
따로 메서드명을 선언하지 않아도 되는 이유는 함수형 인터페이스의 특징인 하나의 추상 메서드만을 가지고 있기 때문이다.
메서드는 하나밖에 없기 때문에 굳이 메서드 명을 작성할 필요가 없는것이다.
그렇다면 a + b; 부분은 뭘까?
바로 MyFunction.add() 메서드의 구현부이다.
추상 메서드이기 때문에 메서드를 사용하기 위해선 구현부가 필요한 것이다.
자바의 함수형 인터페이스
자바8부터 기본적으로 함수형 인터페이스를 제공한다.
Runnable (매개변수 없음, 반환값 없음)
Runnable task = () -> System.out.println("Hello");
task.run(); // 출력: Hello
아무 인자도 받지 않고, 반환값도 없는 작업을 실행할 때 사용된다. Runnable.run()메서드만 정의된 함수형 인터페이스이다. 주로 스레드를 실행할 때 사용된다.
Consumer<T> (매개변수 있음, 반환값 없음)
Consumer<String> strToPrint = str -> System.out.println(str.length());
strToPrint.accept("Hello"); // 출력: 5
하나의 인자를 받아서 그 인자에 대해 어떤 작업을 수행하지만, 반환값은 없는 경우 사용한다. Consumer는 인자를 받아서 처리하는 작업을 정의하는 함수형 인터페이스이다. Consumer의 accept() 메서드를 통해 작업을 수행한다.
Function<T, R> (매개변수 있음, 반환값 있음)
Function<Integer, String> intToString = num -> "Number: " + num;
System.out.println(intToString.apply(10)); // 출력: Number: 10
인자를 받아서 변환 작업을 수행하고, 결과를 반환하는 함수형 인터페이스이다. Function은 입력값을 받아 변환하여 반환하는 역할을 수행한다. apply() 메서드로 변환 작업을 실행한다.
Predicate<T> (매개변수 있음, 반환값: boolean)
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(2)); // 출력: true
System.out.println(isEven.test(3)); // 출력: false
인자를 받아서 true 또는 false를 반환하는 조건 검사에 사용된다. Predicate는 조건을 검사하는 함수형 인터페이스로, test() 메서드를 사용해 인자가 조건을 만족하는지 검사한다.
Supplier<T> (매개변수 없음, 반환값 있음)
Supplier<String> returnMessage = () -> "Hello";
System.out.println(returnMessage.get()); // 출력: Hello
인자는 받지 않고, 결과를 반환하는 함수형 인터페이스이다. Supplier는 인자 없이 값을 생성하거나 제공하는 데 사용된다. get() 메서드로 값을 반환한다.
함수형 인터페이스가 사용되는 이유
그렇다면 왜 저런 함수형 인터페이스를 따로 추출해 사용하는 것일까?
바로 람다식과의 조합이 너무 좋기 때문이다.
람다식을 사용하면 익명 클래스를 사용하는 것보다 훨씬 더 간결한 코드를 작성할 수 있다.
평소에 익명 클래스를 사용할 땐 클래스 선언, 변수 선언, 메서드 선언, 메서드 오버라이딩 등 코드가 너무 많이 들어간다.
하지만 람다식은 간단한 구문으로 동일한 기능을 구현할 수 있다.
// 익명 클래스 사용 (길고 복잡함)
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// 람다식 사용 (간결하고 직관적)
Runnable runnable = () -> System.out.println("Hello");
함수형 인터페이스는 하나의 추상 메서드만 가지므로, 람다식과 함께 사용하면 코드가 짧고 명확해진다.
'개발 일기' 카테고리의 다른 글
[개발 일기] 2025.01.22 - static (0) | 2025.01.22 |
---|---|
[개발 일기] 2025.01.21 - TCP/IP (0) | 2025.01.21 |
[개발 일기] 2025.01.19 - JWT(JWS, JWE) (0) | 2025.01.19 |
[개발 일기] 2025.01.18 - Collectors (1) | 2025.01.18 |
[개발 일기] 2025.01.17 - SSL (1) | 2025.01.17 |