[java]함수형 인터페이스, 람다식&Stream (1)

송어·2023년 11월 20일

함수형 인터페이스

함수형 인터페이스란, 단 하나의 추상 메서드를 가진 인터페이스를 의미한다. 함수형 인터페이스는 @FunctionalInterface 어노테이션을 사용해 표시할 수 있다.

@FunctionalInterface는 선택 사항이지만 컴파일러에게 해당 인터페이스가 함수형 인터페이스임을 알려주는 역할을 한다.

다음은 함수형 인터페이스 구현과 사용방법에 관한 예시이다.

@FunctionalInterface // 함수형 인터페이스
interface MathOperation {
	int operation(int x, int y);
}

public class FunctionInterfaceTest implements MathOperation {
    public static void main(String[] args) {
        MathOperation mo1 = new FunctionInterfaceTest(); // 함수형 인터페이스 사용 방법 1 : 추상메서드 구현
        int result1 = mo1.operation(10, 20);
        System.out.println("방법 1 result : " + result1);

        System.out.println("++++++++++++++++++");

        MathOperation mo2 = new MathOperationImpl();
        int result2 = mo1.operation(10, 20);
        System.out.println("방법 2 result : " + result2); // 함수형 인터페이스 사용 방법 2 : 구현체 사용

        System.out.println("++++++++++++++++++");

        MathOperation mo3 = new MathOperation() { // 함수형 인터페이스 사용 방법 3 : (내부)익명클래스 사용(인터페이스는 존재하지만 구현 클래스가 존재하지 않음)
            @Override
            public int operation(int x, int y) {
                return x + y;
            }
        };
        int result3 = mo3.operation(10, 20);
        System.out.println("방법 3 result : " + result3);
    }

    @Override
    public int operation(int x, int y) {
        return x + y;
    }
}

첫번째와 두번째 방법은 일반적으로 인터페이스를 사용하는 방법이다. 세번째 방법은 인터페이스는 존재하지만 실제 구현체는 존재하지 않는 익명클래스를 사용하는 방법이다. 위 코드를 살펴보면 new연산자로 인터페이스를 생성함과 동시에 중괄호를 사용해 바로 메서드를 구현한다.

함수형 인터페이스를 사용하는 이유

  1. 람다식 지원
  2. 메서드 참조
  3. StreamAPI와의 통합
  4. 병렬 프로그래밍
  5. 코드 재사용

메서드 참조

자바에서는 이미 정의된 메서드를 직접 참조해 람다 표현식을 더욱 간결하게 만들 수 있다. 메서드 참조는 기존 메서드를 재사용하고 코드 중복을 줄이는데 큰 도움을 준다.

메서드 참조 유형

1. 정적 메서드 참조 : 클래스명::메서드명

public class IntegerUtilsTest {
    public static void main(String[] args) {
        Converter<String, Integer> converter = IntegerUtils::stringToInt; // 정적(static) 메서드 참조
        int result = converter.convert("123"); // Auto-unboxing
        System.out.println("result : " + result);
    }
}
  • 함수형 인터페이스를 메서드 참조를 활용해 간편하게 사용
  • 함수형 인터페이스 converter로 구현 후 IntegerUtils의 stringToInt를 참조해 코드를 간결하게 만들었다.

2. 인스턴스 메서드 참조 : 객체참조::메서드명

public class StringUtilsTest {
    public static void main(String[] args) {
        StringUtils stringutils = new StringUtils();
        Converter<String, String> converter = stringutils::reverse; // 인스턴스 메서드 참조
        String result = converter.convert("hello");
        System.out.println("result : " + result);
    }
}
  • 객체를 생성 후 해당 객체의 메서드를 참조해 함수형 인터페이스를 사용하는 예시

3. 특정 객체의 인스턴스 메서드 참조 : 클래스명::메서드명

public class SortCompareTest {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("김수현", "조용진", "배수지", "박보영", "이상순", "유재석"); // 특정 객체의 인스턴스 메서드 참조
        Collections.sort(list, String::compareTo);
        System.out.println(list);

        for(String name : list) {
            System.out.println(name);
        }
    }
}
  • 여기서 특정 객체라 함은 이미 만들어져있는 자바API를 말한다.
  • 본 예시에서는 String class의 인스턴스메서드인 compareTo를 사용했다.( String::compareTo )

4. 생성자 참조 : 클래스명::new

public class PersonFactoryTest {
    public static void main(String[] args) {
        PersonFactory personFactory1 = Person::new; // 생성자 참조 : Person의 생성자를 참조해 객체 생성
        Person person1 = personFactory1.create("홍길동", 25); // 생성자 참조를 활용한 객체생성
        System.out.println(person1);

        PersonFactory personFactory2 = new PersonFactory() { // 익명 클래스를 활용한 객체생성 : 메서드 참조에 비해 코드가 복잡하고 길다
            @Override
            public Person create(String name, int age) {
                return new Person(name, age);
            }
        };
        Person person2 = personFactory2.create("이몽룡", 28);
        System.out.println(person2);
    }
}
  • new 생성자를 참조해 객체를 생성하는 코드를 구현하고, 코드 길이 및 복잡도 비교를 위해 동일한 기능을 하는 익명 클래스를 만들었다.
  • 생성자를 참조해 객체를 생성하는 결과는 같지만 메서드 참조에 비해 익명 클래스 사용은 코드도 더 길고 복잡하다는 것을 알 수 있다.

0개의 댓글