공부방/JAVA

자바 함수형 인터페이스

들어가며

자바 8에서 도입된 함수형 인터페이스(Functional Interface)는 현대 자바 프로그래밍의 핵심 개념 중 하나입니다. 람다식과 스트림 API의 기반이 되는 함수형 인터페이스에 대해 알아보겠습니다.

함수형 인터페이스란?

함수형 인터페이스는 단 하나의 추상 메서드만을 가지는 인터페이스를 의미합니다. Java 8부터 도입되었으며, @FunctionalInterface 어노테이션을 통해 함수형 인터페이스임을 명시적으로 선언할 수 있습니다.

예시:

@FunctionalInterface  
public interface SimpleFunction {  
    void doSomething();  
}  

주요 함수형 인터페이스

1. Function<T,R>

  • 입력값 하나와 리턴값이 있는 가장 기본적인 함수형 인터페이스
  • R apply(T t) 메서드를 가짐
Function<T, R>
    R apply(T t)

예시

Function<String, Integer> strLength = str -> str.length();  
System.out.println(strLength.apply("Hello")); // 출력: 5  

2. Predicate

  • 조건식을 표현하는데 사용(매개변수 하나)
  • boolean 값을 리턴하는 test(T t) 메서드를 가짐
Predicate<T>
    boolean test(T t)

예시

Predicate isEmpty = str -> str.isEmpty();  
System.out.println(isEmpty.test("")); // 출력: true  

3. Consumer

  • 입력값만 있고 리턴값이 없는 인터페이스
  • void accept(T t) 메서드를 가짐
Consumer<T>
    void accept(T t)

예시

Consumer printer = str -> System.out.println(str);  
printer.accept("Hello World"); // 출력: Hello World  

4. Supplier

  • 입력값 없이 리턴값만 있는 인터페이스
  • T get() 메서드를 가짐
Supplies<T>
    T get()
Supplier random = () -> Math.random();  
System.out.println(random.get()); // 랜덤값 출력

함수형 인터페이스의 장점

  1. 간결한 코드
    • 람다식을 통해 익명 클래스를 더 간단하게 표현할 수 있습니다.
  2. 재사용성
    • 공통적인 함수형 인터페이스를 여러 곳에서 재사용할 수 있습니다.
  3. 유연성
    • 다양한 동작을 하나의 메서드로 처리할 수 있습니다.

커스텀 함수형 인터페이스 생성

@FunctionalInterface  
interface MathOperation {  
    int operate(int a, int b);
}

public class Calculator {  
    public static void main(String\[\] args) {  
        MathOperation addition = (a, b) -> a + b;  
        MathOperation multiplication = (a, b) -> a \* b;

        System.out.println(addition.operate(5, 3));        // 출력: 8 
        System.out.println(multiplication.operate(5, 3));  // 출력: 15  
    }
}

주의사항

  1. 단일 추상 메서드
    • 함수형 인터페이스는 반드시 하나의 추상 메서드만 가져야 합니다.
    • default 메서드나 static 메서드는 여러 개 가질 수 있습니다.
  2. @FunctionalInterface 어노테이션
    • 선택사항이지만, 컴파일 타임에 검증을 위해 사용을 권장합니다.

람다 표현식이란?

람다 표현식은 간단히 말해서 "메서드를 하나의 식으로 표현한 것"입니다. 익명 함수(Anonymous Function)를 생성하기 위한 식으로, Java 8부터 도입되었습니다.

(매개변수) -> { 실행문 }

람다 표현식의 다양한 형태

1. 가장기본적인 형태

// 기존 방식
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello");
    }
};

// 람다 표현식
Runnable runnable = () -> System.out.println("Hello");

2. 매개변수가 있는 경우

// 매개변수 한 개
Consumer<String> consumer = (String str) -> System.out.println(str);
// 매개변수 타입 생략 가능
Consumer<String> consumer = str -> System.out.println(str);
// 매개변수 여러 개
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;

3. 본문이 여러줄인 경우

BiFunction<Integer, Integer, Integer> calculate = (x, y) -> {
    int result = x + y;
    System.out.println("결과: " + result);
    return result;
};

실제 활용 예시

1. 컬렉션 처리

BiFunction<Integer, Integer, Integer> calculate = (x, y) -> {
    int result = x + y;
    System.out.println("결과: " + result);
    return result;
};

2. 스트림 API와 함께 사용

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 필터링, 매핑, 집계 연산
int sum = numbers.stream()
    .filter(n -> n % 2 == 0)        // 짝수 필터링
    .map(n -> n * 2)                // 2배로 변환
    .reduce(0, (a, b) -> a + b);    // 합계 계산

3. 이벤트 처리

button.addActionListener(e -> System.out.println("버튼 클릭됨"));

람다 표현식의 장점:

  1. 코드의 간결성: 불필요한 코드를 줄여줍니다
  2. 가독성 향상: 의도를 더 명확하게 표현할 수 있습니다
  3. 함수형 프로그래밍 지원: 함수를 일급 객체처럼 다룰 수 있습니다
  4. 병렬 처리 용이: 컬렉션의 병렬 처리를 더 쉽게 구현할 수 있습니다

주의사항:

  1. 람다 표현식 내에서 사용되는 지역변수는 final이거나 effectively final이어야 합니다
  2. 람다 표현식에서 this는 람다를 감싸는 클래스를 가리킵니다
  3. 너무 복잡한 로직을 람다로 표현하면 오히려 가독성이 떨어질 수 있습니다

결론

함수형 인터페이스는 자바의 함수형 프로그래밍을 가능하게 하는 핵심 요소입니다. 람다식과 함께 사용하면 더 간결하고 읽기 쉬운 코드를 작성할 수 있으며, 스트림 API와 결합하여 강력한 데이터 처리 기능을 구현할 수 있습니다.

적절한 상황에서 함수형 인터페이스를 활용하면 코드의 가독성과 유지보수성을 크게 향상시킬 수 있습니다. 특히 자바 8 이상을 사용하는 프로젝트에서는 필수적으로 알아야 할 개념이라고 할 수 있습니다.