본문 바로가기

Java 길찾기/이것이 자바다

[Java] 표준 API의 함수적 인터페이스 - Operator, Predicate

Operator 함수적 인터페이스

Operator 함수적 인터페이스는 Function과 동일하게 매개 변수와 리턴값이 있는 applyXXX() 메소드를 가지고 있다. 하지만 이 메소드들은 매개값을 리턴값으로 매핑(타입 변환)하는 역할보다는 매개값을 이용해서 연산을 수행한 후 동일한 타입으로 리턴값을 제공하는 역할을 한다.

매개 변수의 타입과 수에 따라서 아래와 같은 Operator 함수적 인터페이스들이 있다.

인터페이스명 추상 메소드 설명
BinaryOperator<T> T apply(Tt, Tt) T와 T를 연산한 후 T 리턴
UnaryOperator<T> T apply(Tt) T를 연산한 후 T 리턴
DoubleBinaryOperator double applyAsDouble(double, double) 두 개의 double 연산
DoubleUnaryOperator double applyAsDouble(double) 한 개의 double 연산
IntBinaryOperator int applyAsInt(int, int) 두 개의 int 연산
IntUnaryOperator int applyAsInt(int) 한 개의 int 연산
LongBinaryOperator long applyAsLong(long, long) 두 개의 long 연산
LongUnaryOperator long applyAsLong(long) 한 개의 long 연산

 

IntBinaryOperator 인터페이스를 타겟 타입으로 하는 람다식은 다음과 같이 작성할 수 있다. applyAsInt() 메소드는 매개값으로 두 개의 int 를 가지므로 람다식도 두 개의 int 매개 변수 a와 b를 사용한다. 그리고 applyAsInt() 메소드의 리턴 타입이 int 이므로 람다식의 중괄호 { }의 리턴값은 int가 된다. 다음 코드는 두 개의 int를 연산해서 결과값으로 int를 리턴한다.

IntBinaryOperator operator = (a, b) -> { ...; return int값; }

 

다음 예제는 int[ ] 배열에서 최대값과 최소값을 얻는다. maxOrMin() 메소드는 IntBinaryOperator 매개 변수를 가지고 있다. 따라서 masOrMin() 메소드를 호출할 때 람다식을 사용할 수 있다.

// OperatorExample.java -- Operator 함수적 인터페이스
import java.util.function.IntBinaryOperator;

public class OperatorExample {
    private static int[] scores = { 92, 95, 87 };
    
    public static int maxOrMin(IntBinaryOperator operator) {
        int result = scores[0];
        for(int score : scores) {
            result = operator.applyAsInt(result, score);
        }
        return result;
    }
    
    public static void main(String[] args) {
        // 최대값 얻기
        int max = maxOrMin(
            (a, b) -> {
                if(a>=b) return a;
                else return b;
            }
        );
        System.out.println("최대값: " + max);
        
        // 최소값 얻기
        int min = maxOrMin(
            (a, b) -> {
                if(a<=b) return a;
                else return b;
            }
        );
        System.out.println("최소값: " + min);
    }
}

 

Predicate 함수적 인터페이스

Predicate 함수적 인터페이스는 매개 변수와 boolean 리턴값이 있는 testXXX() 메소드를 가지고 있다. 이 메소드들은 매개값을 조사해서 true 또는 false를 리턴하는 역할을 한다.

매개 변수 타입과 수에 따라서 아래와 같은 Predicate 함수적 인터페이스들이 있다.

인터페이스명 추상 메소드 설명
Predicate<T> boolean test(T t) 객체 T를 조사
BiPredicate<T, U> boolean test(T t, U u) 객체 T와 U를 비교 조사
DoublePredicate boolean test(double value) double 값을 조사
IntPredicate boolean test(int value) int 값을 조사
LongPredicate boolean test(long value) long 값을 조사

 

Predicate<T> 인터페이스를 타겟 타입으로 하는 람다식은 다음과 같이 작성할 수 있다. test() 메소드는 매개값으로 T 객체 하나를 가지므로 람다식도 한 개의 매개 변수를 사용한다. 그리고 test() 메소드의 리턴 타입이 boolean이므로 람다식 중괄호 { }의 리턴값은 boolean이 된다. T가 Student 타입이므로 t 매개 변수 타입은 Student가 된다. t.getGender()는 Student 객체의 getGender() 메소드를 호출해서 "남자" 또는 "여자"를 얻는다. 결국 다음 코드는 String의 equals() 메소드를 이용해서 남학생만 true를 리턴한다.

Predicate<Student> predicate = t -> { return t.getGender().equals("남자"); }
또는
Predicate<Student> predicate = t -> t.getGender().equals("남자");

 

다음 예제는 List에 저장된 남자 또는 여자 학생들의 평균 점수를 출력한다. avg() 메소드는 Predicate<Student> 매개 변수를 가지고 있다. 따라서 avg() 메소드를 호출할 때 매개값으로 람다식을 사용할 수 있다.

// PredicateExample.java -- Predicate 함수적 인터페이스
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class PredicateExample {
    private static List<Student> list = Arrays.asList(
            new Student("홍길동", "남자", 90),
            new Student("김자바", "남자", 95),
            new Student("순순희", "여자", 90),
            new Student("박하나", "여자", 92)
    );
    
    public static double avg(Predicate<Student> predicate) {
        int count = 0, sum = 0;
        for(Student student : list) {
            if(predicate.test(student)) {
                count++;
                dum += student.getScore();
            }
        }
        return (double) sum / count;
    }
    
    public static void main(String[] args) {
        double maleAvg = avh( t -> t.getGender().equals("남자"));
        System.out.println("남자 평균 점수: " + maleAvg);

        double femaleAvg = avh( t -> t.getGender().equals("여자"));
        System.out.println("여자 평균 점수: " + femaleAvg);
    }
}
// Student.java -- Student 클래스
public class Student {
    
    private String name;
    private String gender;
    private int score;
        
    public Student(String name, String gender, int score) {
        this.name = name;
        this.gender = gender;
        this.score = score;
    }
        
    public String getGender() { return gender; }
    public int getScore() { return score; }
}