[Java] 함수형 인터페이스와 람다식

유콩·2022년 3월 2일
2

함수형 인터페이스(Functional Interface)

함수형 인터페이스란 하나의 추상 메서드를 가지는 인터페이스 를 말한다.

public interface MyInterface {

	public abstract void max(int a, int b);
}

본래 인터페이스는 다음과 같이 구현한다.

public class MyClass implements MyInterface {
	
    @Override
    public void max(int a, int b) {
    	return a > b ? a : b;
    }
}

왜 단 하나의 추상 메서드를 가지는 인터페이스를 선언할까? 그건 자바 8에 추가된 람다식을 표현하기 위해 사용된다. 먼저, 함수형 인터페이스를 별도의 클래스로 구현하는 것이 아닌 익명 클래스로 구현하면 다음과 같이 생성할 수 있다.

Myfunction f = new MyFunction() {
					public int max(int a, int b) {
                    	return a > b ? a : b;
                    }
               };
int big = f.max(5, 3);

위 코드를 람다식을 활용하여 축약하면 다음과 같이 간략하게 표현할 수 있다.

MyFunction f = (int a, int b) -> a > b ? a : b;
int big = f.max(5, 3);

왜 자바는 람다식 표현을 인터페이스로 구현했을까? 하나의 메서드가 선언된 인터페이스를 정의해서 람다식을 다루는 것은 기존의 자바 문법을 활용하여 표현할 수 있기 때문이다. 그래서 인터페이스를 통해 람다식을 다루기로 결정되었으며, 기존 함수의 정의대로 입력과 출력의 형태로 된 람다식을 다루는 인터페이스를 함수형 인터페이스라고 부르기로 했다.

함수형 인터페이스임을 명시하고 싶을 때에는 @FunctionalInterface 를 붙일 수 있다. 생략할 수 있으며 어노테이션을 붙이고 두개 이상의 추상 메서드를 선언하면 컴파일 에러가 발생한다.

람다식의 활용

우테코 미션을 진행하면서 결과값을 지정할 수 없어 테스트하기 어려운 메서드를 함수형 인터페이스로 분리하여 람다식으로 값을 지정하고 테스트 하였다.

1. 랜덤 결과값에 따른 메서드 동작

랜덤에 따른 결과에 따라 메서드의 동작이 달랐다. 랜덤 결과를 람다식을 이용해 예상 값을 지정하고 주 메서드의 동작을 테스트하였다.

public class CarTest {

    @DisplayName("자동차가 이동하는 경우")
    @Test
    void car_drive_true() {
        Car carDrive = new Car("drive");

        Movable movable = () -> true; // 값 임의 지정
        carDrive.drive(movable); // 테스트하려는 메서드

        assertEquals(carDrive.getPosition(), 1);
    }

    @DisplayName("자동차가 대기하는 경우")
    @Test
    void car_drive_false() {
        Car carDrive = new Car("drive");

        Movable movable = () -> false; // 값 임의 지정
        carDrive.drive(movable); // 테스트하려는 메서드

        assertEquals(carDrive.getPosition(), 0);
    }
}

2. 사용자 입력값에 따른 메서드 동작

객체를 생성하기 위해 사용자의 입력값을 받을 때, 적절한 입력값인지 검증해야 했다. 람다식을 이용하여 예상 입력값을 임의로 지정하여 그에 따른 테스트를 추가하였다.

class InputTest {

    @Test
    @DisplayName("구입 금액에 null 을 입력할 경우")
    void payment_null() {
        assertThatThrownBy(() -> {
            Entering entering = () -> null; // 값 임의 지정
            int payment = inputPayment(entering); // 테스트하려는 메서드
        }).isInstanceOf(IllegalArgumentException.class);
    }

    @Test
    @DisplayName("구입 금액에 빈값을 입력했을 경우")
    void payment_empty() {
        assertThatThrownBy(() -> {
            Entering entering = () -> ""; // 값 임의 지정
            int payment = inputPayment(entering); // 테스트하려는 메서드
        }).isInstanceOf(IllegalArgumentException.class);
    }

    @Test
    @DisplayName("구입 금액에 문자를 입력했을 경우")
    void payment_not_number() {
        assertThatThrownBy(() -> {
            Entering entering = () -> "payment"; // 값 임의 지정
            int payment = inputPayment(entering); // 테스트하려는 메서드
        }).isInstanceOf(IllegalArgumentException.class);
    }
 }

참고

0개의 댓글

관련 채용 정보