Java/함수형 인터페이스

[Java]BinaryOperator 인터페이스 사용 방법

DevStory 2022. 8. 23.

BinaryOperator 인터페이스

BinaryOperator Interface는 Java에서 함수형 프로그래밍을 구현하기 위해 Java 버전 1.8부터 도입된 함수형 인터페이스로 두 개의 매개변수를 비교하는 목적으로 사용합니다.

 

BinaryOperator 인터페이스는 인수와 반환 타입이 전부 동일하며, BiFunction 인터페이스를 확장합니다.

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
  public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
    Objects.requireNonNull(comparator);
    return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
  }

  public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
    Objects.requireNonNull(comparator);
    return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
  }
}

BiFunction 인터페이스를 확장하므로 BiFunction 인터페이스 내부의 다음 메서드를 상속합니다.

- 추상 메서드인 apply() 메서드

- 디폴트 메서드인 andThen() 메서드

 

람다 표현식을 사용하면 추상 메서드인 apply() 메서드를 구현하기 위해 클래스를 정의할 필요가 없으며,  BinaryOperator 타입의 객체에 할당된 람다 표현식은 apply() 메서드를 구현하기 위해 사용됩니다.


BinaryOperator 인터페이스의 minBy 메서드

minBy() 메서드는 매개변수로 전달된 비교자(Comparator)를 기반으로 apply() 메서드로 전달된 두 매개변수를 비교 후 작은 값을 반환합니다.

public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
  Objects.requireNonNull(comparator);
  return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
}

다음 예제는 BinaryOperator 타입의 객체를 생성하고 값을 오름차순으로 비교하는 Comparator 비교자를 minBy() 메서드에 전달합니다.

 

다음으로 apply() 메서드에 첫 번째 매개변수로 50, 두 번째 매개변수로 100을 전달합니다. 

public static void main(String args[]) {
  // 두 객체를 오름차순으로 비교하는 비교자를 생성
  Comparator<Integer> integerComparator =
          Comparator.naturalOrder();

  // BinaryOperator 객체 생성
  // BinaryOperator.minBy(integerComparator)가 apply() 메서드에서 동작
  BinaryOperator<Integer> intBinaryOperator =
          BinaryOperator.minBy(integerComparator);

  System.out.println("50, 100 중 최소값: " +
          intBinaryOperator.apply(50, 100));
}

[실행 결과]

50, 100 중 최소값: 50

BinaryOperator 인터페이스의 maxBy 메서드

maxBy() 메서드는 minBy() 메서드와 반대로 두 매개변수를 비교 후 큰 값을 반환합니다.

public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
  Objects.requireNonNull(comparator);
  return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
}

다음 예제는 BinaryOperator 타입의 객체를 생성하고 값을 오름차순으로 비교하는 Comparator 비교자를 maxBy() 메서드에 전달합니다.

 

다음으로 apply() 메서드에 첫 번째 매개변수로 50, 두 번째 매개변수로 100을 전달합니다. 

public static void main(String args[]) {
  // 두 객체를 오름차순으로 비교하는 비교자를 생성
  Comparator<Integer> integerComparator =
          Comparator.naturalOrder();

  // BinaryOperator 객체 생성
  // BinaryOperator.maxBy(integerComparator)가 apply() 메서드에서 동작
  BinaryOperator<Integer> intBinaryOperator =
          BinaryOperator.maxBy(integerComparator);

  System.out.println("50, 100 중 최대값: " +
          intBinaryOperator.apply(50, 100));
}

[실행 결과]

50, 100 중 최대값: 100

BiFunction 인터페이스의 andThen 메서드

BinaryOperator 인터페이스는 BiFunction 인터페이스를 상속하므로 BiFunction 인터페이스의 디폴트 메서드인 andThen() 메서드를 호출할 수 있습니다.

 

BinaryOperator 타입의 객체에서 andThen() 메서드 호출 후 apply() 메서드를 호출합니다.

 

다음 예제는 10을 곱하는 람다 표현식을 andThen() 메서드에 전달 후 apply() 메서드를 호출합니다.

 

andThen() 메서드가 먼저 실행되었지만, 10을 곱하는 람다 표현식은 apply() 메서드 실행이 끝난 후 동작합니다.

public static void main(String args[]) {
  // 두 객체를 오름차순으로 비교하는 비교자를 생성
  Comparator<Integer> integerComparator =
          Comparator.naturalOrder();

  // BinaryOperator 객체 생성
  // BinaryOperator.maxBy(integerComparator)가 apply() 메서드에서 동작
  BinaryOperator<Integer> intBinaryOperator =
          BinaryOperator.maxBy(integerComparator);

  System.out.println("50, 100 중 최대값: " +
          intBinaryOperator.andThen(num -> num * 10).apply(50, 100));
}

[실행 결과]

50, 100 중 최대값: 1000

andThen() 메서드는 다음 소스 코드처럼 여러번 연결하여 호출할 수 있습니다.

 

다음 예제를 실행한 결과를 보면 다음 순서대로 동작합니다.

 

[실행 순서]

순서 1. apply() 메서드 동작

순서 2. 첫 번째 andThen() 메서드의 람다 표현식 동작

순서 3. 두 번째 andThen() 메서드의 람다 표현식 동작

순서 4. 세 번째 andThen() 메서드의 람다 표현식 동작

public static void main(String args[]) {
  // 두 객체를 오름차순으로 비교하는 비교자를 생성
  Comparator<Integer> integerComparator =
          Comparator.naturalOrder();

  // BinaryOperator 객체 생성
  // BinaryOperator.maxBy(integerComparator)가 apply() 메서드에서 동작
  BinaryOperator<Integer> intBinaryOperator =
          BinaryOperator.maxBy(integerComparator);

  System.out.println("andThen() 메서드 호출 결과: " +
          intBinaryOperator
                  .andThen(num -> num * 10)
                  .andThen(num -> Math.pow(num, 2))
                  .andThen(num -> num + 1)
                  .apply(50, 100));
}

[실행 결과]

andThen() 메서드 호출 결과: 1000001.0

사용자가 정의한 클래스 타입의 객체를 비교

사용자가 정의한 클래스 타입의 객체에서 특정 프로퍼티를 기준으로 두 객체를 비교 후 최소값 또는 최대값을 가져와야 하는 경우가 있을 수 있습니다.

 

이러한 경우 Comparator<T> 타입의 비교자 객체를 생성하지 않고 특정 프로퍼티를 비교하는 로직을 maxBy() 메서드 또는 minBy() 메서드에 바로 할당합니다.

 

다음 예제는 Person 타입의 두 객체에서 Age 프로퍼티의 값이 큰 객체를 가져옵니다.

 

[Person 클래스]

public class Person {
  private String Name;
  private Integer Age;

  public Person(String name, Integer age) {
    Name = name;
    Age = age;
  }

  public String getName() {
    return Name;
  }

  public Integer getAge() {
    return Age;
  }

  @Override
  public String toString() {
    return "Person{Name='" + Name + "\', Age=" + Age + "}";
  }
}

[Main문]

public static void main(String args[]) {
  Person person1 = new Person("둘리", 25);
  Person person2 = new Person("또치", 30);

  BinaryOperator<Person> intBinaryOperator =
          BinaryOperator.maxBy(
                  (Person item1, Person item2) -> item1.getAge() - item2.getAge());

  System.out.println("Age 프로퍼티의 값이 큰 Person 객체: " +
          intBinaryOperator.apply(person1, person2));
}

[실행 결과]

Age 프로퍼티의 값이 큰 Person 객체: Person{Name='또치', Age=30}
반응형

댓글