Welcome! Everything is fine.

[TIL] enum 클래스에 연산자 담기, BiFunction 인터페이스 본문

TIL

[TIL] enum 클래스에 연산자 담기, BiFunction 인터페이스

개발곰발 2025. 1. 8. 23:35
728x90

enum 사용하기

LV.3 계산기 구현을 시작했는데, enum 타입으로 연산자 타입에 대한 정보를 관리해야한다는 요구사항을 보고 고민에 빠졌다.

 

처음에는 이런 식으로 하라는 건가? 했는데, 이미 Lv.2 계산기를 할 때 switch문에서 잘못된 연산자를 입력 받지 못하게 했기 때문에 enum을 왜 써야하는지 의문이었다. 사칙연산을 그대로 enum에 집어넣을 수 있다면 몰라도...?

public enum OperatorType {
    ADD("+"),
    SUBTRACT("-"),
    MULTIPLY("*"),
    DIVIDE("/")
}

 

알고보니 정말 집어넣을 수 있었다. enum 상수마다 동작을 다르게 정의해야 할 때 익명 클래스를 사용해 각 상수별로 고유한 메서드 구현을 할 수 있다.

public enum Operation {
    ADD {
        @Override
        public double operate(double x, double y) {
            return x + y;
        }
    },
    SUBTRACT {
        @Override
        public double operate(double x, double y) {
            return x - y; 
        }
    },
    MULTIPLY {
        @Override
        public double operate(double x, double y) {
            return x * y; 
        }
    },
    DIVIDE {
        @Override
        public double operate(double x, double y) {
            if (y == 0) {
                throw new ArithmeticException("0으로 나눌 수 없습니다.");
            }
            return x / y; 
        }
    };

    // 추상 메서드 선언
    public abstract double operate(double x, double y);
}

 

혹은 다음과 같이 람다식을 사용해 더 간결하게 작성할 수도 있다. 간단한 로직이므로 람다식으로 표현하는 것이 더 적합해보인다. 람다식만 적었다고 되는 것이 아니라, 람다식을 받는 생성자와 필드를 정의해줘야 한다.

public enum OperatorType {
    ADD((a, b) -> a + b),
    SUBTRACT((a, b) -> a - b),
    MULTIPLY((a, b) -> a * b),
    DIVIDE((a, b) -> {
        if (b == 0) throw new ArithmeticException("0으로 나눌 수 없습니다.");
        return a / b;
    });
    
    private final BiFunction<Double, Double, Double> operation;
    
    OperatorType(BiFunction<Double, Double, Double> operation) {
        this.operation = operation;
    }
    
    public double apply(double a, double b) {
        return operation.apply(a, b);
    }
}

 

여기서 BiFunction은 두 개의 입력값(T, U)을 받아서 하나의 출력값(R)을 반환하는 함수형 인터페이스이다. OperatorType 열거형은 각 연산(람다식)을 생성자에 전달받아 operation 필드에 저장한다. apply() 메서드는 저장된 operation 필드(람다식)를 호출하여 실제 연산을 수행하는 역할을 한다.

 

operation.apply(a, b)에서 볼 수 있듯이 BiFunction 인터페이스에 apply() 메서드가 있다. 찾아보니 다음과 같이 먼저 BiFunction 객체에 특정 로직을 수행하는 람다 표현식을 할당한 후, apply() 메서드로 두 개의 매개변수를 전달받아 특정 작업을 수행 후 값을 반환하게 된다.

BiFunction<Integer, Integer, String> biFunctionAdd =
          (num1, num2) ->  Integer.toString(num1 + num2);
          
System.out.println("100 + 50 = " + biFunctionAdd.apply(100, 50));