ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java - 표준 API의 함수적 인터페이스
    Language/Java 2022. 11. 30. 11:28

    표준 API의 함수적 인터페이스

    Java8부터는 java.util.function 표준 API 패키지를 통해 빈번하게 사용되는 함수적 인터페이스가 제공된다. 이 패키지 안에 있는 함수적 인터페이스들을 크게 Consumer, Supplier, Function, Operator, Predicate로 구분할 수 있다.

     

    Consumer 함수적 인터페이스

     

    인터페이스명 추상 메서드 설명
    Consumer<T> void accept(T t) 객체를 T를 받아 소비
    BiConsumer<T, U> void accept(T t, U u) 객체 T, U를 받아 소비
    DoubleConsumer void accept(double value) double 값을 받아 소비
    intConsumer void accept(int value) int 값을 받아 소비
    LongConsumer void accept(long value) long 값을 받아 소비
    ObjDoubleConsumer<T> void accpet(T t, double value) 객체 T, double 값을 받아 소비
    ObjIntConsumer<T> void accept(T t, int value) 객체 T, int 값을 받아 소비
    ObjLongConsumer<T> void accept(T t, long value) 객체 T, long 값을 받아 소비

    위 표에서 알 수 있듯이, Consumer 인터페이스는 특정 객체를 소비한다. 소비한다라는 것은 매개 변수를 사용만 하고 리턴하지 않는다는 뜻이다. 그래서 추상 메서드의 리턴 형태가 void가 된다.

     

    public class Student {
        private String name;
    
        public Student(String name) {
            this.name = name;
        }
    
        public String getName() {
            return this.name;
        }
    }

    Consumer 인터페이스의 추상 메서드를 사용하기 위한 객체 Student를 위 코드와 같이 작성한다.

     

    public class Main {
        public static void main(String[] args) {
            Consumer<String> c01 = value -> System.out.println("입력값 : " + value);
            BiConsumer<String, Integer> c02 = (value01, value02) -> System.out.println("입력값01 : " + value01 + ", 입력값02 : " + value02);
            IntConsumer c03 = value -> System.out.println("입력값 : " + value);
            DoubleConsumer c04 = value -> System.out.println("입력값 : " + value);
            LongConsumer c05 = value -> System.out.println("입력값 : " + value);
            ObjIntConsumer<Student> c06 = (student, value) -> System.out.println("이름 : " + student.getName() + ", 숫자 : " + value);
            ObjDoubleConsumer<Student> c07 = (student, value) -> System.out.println("이름 : " + student.getName() + ", 숫자 : " + value);
            ObjLongConsumer<Student> c08 = (student, value) -> System.out.println("이름 : " + student.getName() + ", 숫자 : " + value);
    
            c01.accept("홍길동");   // "입력값 : 홍길동" 출력
            c02.accept("홍길동", 20);   // "입력값01 : 홍길동, 입력값02 : 20" 출력
            c03.accept(30);   // "입력값 : 30" 출력
            c04.accept(3.14);   // "입력값 : 3.14" 출력
            c05.accept(123456);   // "입력값 : 123456" 출력
    
            Student student = new Student("이순신");
            c06.accept(student, 123456);   // "이름 : 이순신, 숫자 : 123456" 출력
            c07.accept(student, 3.14);   // "이름 : 이순신, 숫자 : 3.14" 출력
            c08.accept(student, 123456);   // "이름 : 이순신, 숫자 : 123456" 출력
        }
    }

    위에는 Consumer 인터페이스를 사용한 예시 코드이다.

     

    입력값 : 홍길동
    입력값01 : 홍길동, 입력값02 : 20
    입력값 : 30
    입력값 : 3.14
    입력값 : 123456
    이름 : 이순신, 숫자 : 123456
    이름 : 이순신, 숫자 : 3.14
    이름 : 이순신, 숫자 : 123456

    실행 결과는 위와 같다.

     

    Supplier 함수적 인터페이스

     

    인터페이스명 추상 메서드 설명
    Supplier<T> T get() T 객체를 리턴
    BooleanSupplier boolean getAsBoolean() boolean 값을 리턴
    DoubleSupplier double getAsDouble() double 값을 리턴
    IntSupplier int getAsInt() int 값을 리턴
    LongSupplier long getAsLong() long 값을 리턴

    위 표에서 알 수 있듯이, Supplier 인터페이스는 특정 값을 리턴한다. 이때, 주의해야 할 점은 이 인터페이스는 매개변수를 갖지 않는다는 것이다. 따라서, 람다 바디 내에서 변수를 정의한 후 값을 리턴하도록 설계해야 한다.

     

    public class Main {
        public static void main(String[] args) {
            String stringValue = "HelloWorld";
            boolean booleanValue = true;
            double doubleValue = 3.14;
            int intValue = 123;
            int longValue = 123456;
    
            Supplier<String> supplier = () -> stringValue;
            BooleanSupplier booleanSupplier = () -> booleanValue;
            DoubleSupplier doubleSupplier = () -> doubleValue;
            IntSupplier intSupplier = () -> intValue;
            LongSupplier longSupplier = () -> longValue;
    
            String s = supplier.get();
            System.out.println("String 값 : " + s);   // "String 값 : HelloWorld" 출력
    
            boolean b = booleanSupplier.getAsBoolean();
            System.out.println("boolean 값 : " + b);   // "boolean 값 : true" 출력
    
            double d = doubleSupplier.getAsDouble();
            System.out.println("String 값 : " + d);   // "String 값 : 3.14" 출력
    
            int i = intSupplier.getAsInt();
            System.out.println("int 값 : " + i);   // "int 값 : 123" 출력
    
            long l = longSupplier.getAsLong();
            System.out.println("long 값 : " + l);   // "long 값 : 123456" 출력
        }
    }

    위에는 Supplier 인터페이스를 사용한 예시 코드이다.

     

    String 값 : HelloWorld
    boolean 값 : true
    String 값 : 3.14
    int 값 : 123
    long 값 : 123456

    실행 결과는 위와 같다.

     

    Function 함수적 인터페이스

     

    인터페이스명 추상 메서드 설명
    Function<T, R> R apply(T t) 객체 T를 R로 매핑
    BiFunction<T, U, R> R apply(T t, U u) 객체 T, U를 객체 R로 매핑
    DoubleFunction<R> R apply(double value) double를 객체 R로 매핑
    IntFunction<R> R apply(int value) int를 객체 R로 매핑
    IntToDoubleFunction double applyAsDouble(int value) int를 double로 매핑
    IntToLongFunction long applyAsLong(int value) int를 long으로 매핑
    LongToDoubleFunction double applyAsDouble(long value) long을 double로 매핑
    LongToIntFunction int applyAsInt(long value) long을 double로 매핑
    toDoubleBiFunction<T, U> double applyAsDouble(T t, U u) 객체 T, U를 double로 매핑

    위 표에서 알 수 있듯이, Function 인터페이스는 매개변수를 리턴 값으로 매핑(타입 변환)한다.

     

    public class Student {
        private int number;
        private String name;
        private int mathGrade;
        private int engGrade;
    
        public Student(int number, String name, int mathGrade, int engGrade) {
            this.number = number;
            this.name = name;
            this.mathGrade = mathGrade;
            this.engGrade = engGrade;
        }
    
        public int getNumber() {
            return number;
        }
    
        public String getName() {
            return name;
        }
    
        public int getMathGrade() {
            return mathGrade;
        }
    
        public int getEngGrade() {
            return engGrade;
        }
    }

    Function 인터페이스의 추상 메서드를 사용하기 위한 객체 Student를 위 코드와 같이 작성한다.

     

    public class Main {
        public static void main(String[] args) {
            Student student = new Student(1, "홍길동", 80, 100);
    
            // 매핑 : Student 객체 -> Student의 Integer 값
            Function<Student, Integer> function = s -> s.getNumber();
            int result01 = function.apply(student);
            System.out.println("Student 번호 : " + result01);
    
            // 매핑 : 두 Integer 값 -> Double 값
            BiFunction<Integer, Integer, Double> biFunction = (math, eng) -> (double) (math + eng) / 2;
            double result02 = biFunction.apply(student.getMathGrade(), student.getEngGrade());
            System.out.println("수학과 영어 성적의 평균 : " + result02);
    
            // 매핑 : Double 값 -> Integer 값
            DoubleFunction<Integer> doubleFunction = x -> {
                Double d = Math.floor(x);
                return d.intValue();
            };
            int result03 = doubleFunction.apply(3.14);
            System.out.println("소수점 버리기 : " + result03);
    
            // 매핑 : 두 Integer 값 -> Double 값
            ToDoubleBiFunction<Integer, Integer> toDoubleBiFunction = (math, eng) -> (double) (math + eng) / 2;
            double result04 = toDoubleBiFunction.applyAsDouble(student.getMathGrade(), student.getEngGrade());
            System.out.println("수학과 영어 성적의 평균 : " + result04);
        }
    }

    위 소스코드는 Function 인터페이스를 사용한 예시 코드이다.

     

    Student 번호 : 1
    수학과 영어 성적의 평균 : 90.0
    소수점 버리기 : 3
    수학과 영어 성적의 평균 : 90.0

    실행결과는 위와 같다.

     

    Operator 함수적 인터페이스

     

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

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

     

    public class Main {
        static private int[] numbers = {3, 7, 2, 5, 1, 9};
        static private double[] celsiusDegrees = {25, 37, 41, 2};
    
        public static void main(String[] args) {
            // 연산식 설정 - 최댓값 구하기
            System.out.println("===== 최댓값 =====");
            int maxValue = getMax(
                    (x, y) -> {
                        int number = x;
                        if (x < y) {
                            number = y;
                        }
                        return number;
                    }
            );
            System.out.println(maxValue);
    
            // 연산식 설정 - 제곱값
            System.out.println("===== 제곱값 =====");
            int[] squareArr = getSquareValue(x -> x * x);
            for (int squareValue : squareArr) {
                System.out.println(squareValue);
            }
    
            // 연산식 설정 - 화씨 온도 바꾸기
            System.out.println("===== 화씨 온도 =====");
            double[] temperatureArr = getTemperature(x -> x * 9 / 5 + 32);
            for (double temperature : temperatureArr) {
                System.out.println(temperature);
            }
        }
        
        // 함수적 인터페이스를 매개 변수 받아 최댓값을 구하는 메서드
        static public int getMax(IntBinaryOperator operator) {
            int result = numbers[0];
            for (int number : numbers) {
                result = operator.applyAsInt(result, number);
            }
            return result;
        }
    
        // 함수적 인터페이스를 매개 변수로 받아 제곱값을 구하는 메서드
        static int [] getSquareValue(IntUnaryOperator operator) {
            int[] intArr = new int[numbers.length];
            for (int i = 0; i < numbers.length; i++) {
                intArr[i] = operator.applyAsInt(numbers[i]);
            }
            return intArr;
        }
    
        // 함수적 인터페이스를 받아 섭씨 온도를 화씨 온도로 바꾸는 메서드
        static double[] getTemperature(DoubleUnaryOperator operator) {
            double[] temperatureArr = new double[celsiusDegrees.length];
            for (int i = 0; i < celsiusDegrees.length; i++) {
                temperatureArr[i] = operator.applyAsDouble(celsiusDegrees[i]);
            }
            return temperatureArr;
        }
    }

    Operator 인터페이스를 활용해 최댓값, 제곱 값, 온도 단위를 화씨로 바꾸기 연산을 수행한다.

     

    ===== 최댓값 =====
    9
    ===== 제곱값 =====
    9
    49
    4
    25
    1
    81
    ===== 화씨 온도 =====
    77.0
    98.6
    105.8
    35.6

    실행결과는 위와 같다.

     

    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 인터페이스는 매개 변수와 boolean 리턴 값이 있는 test() 추상 메서드를 가지고 있다. 해당 메서드는 매개 변수를 조사해서 true 또는 false를 반환하는 역할을 한다.

     

    public class Main {
        static private List<Student> students;
    
        public static void main(String[] args) {
            students = Arrays.asList(
                    new Student("홍길동", Gender.MALE, 90),
                    new Student("이순신", Gender.MALE, 100),
                    new Student("임꺽정", Gender.FEMALE, 85),
                    new Student("이강인", Gender.MALE, 70)
            );
    
            // 남성 평균점수 구하기
            System.out.println("===== 남성 평균점수 =====");
            double avgGradeOfMale = getAvg(x -> x.getGender().equals(Gender.MALE));
            System.out.println(avgGradeOfMale);
    
            // 90점 이상일 경우 평균점수 구하기
            System.out.println("===== 90점 이상일 경우 평균점수 =====");
            double avgOver80 = getAvg(x -> x.getScore() >= 80);
            System.out.println(avgOver80);
        }
    
        static private double getAvg(Predicate<Student> predicate) {
            int count = 0;
            int sum = 0;
            for (Student student : students) {
                if (predicate.test(student)) {
                    count++;
                    sum += student.getScore();
                }
            }
            return (double) sum / count;
        }
    }

    위 소스 코드는 특정 조건에 부합하는 점수만 가져와서 평균으로 구하는 코드이다.

     

    ===== 남성 평균점수 =====
    86.66666666666667
    ===== 90점 이상일 경우 평균점수 =====
    91.66666666666667

    실행결과는 위와 같다.


    출처

    https://steady-coding.tistory.com/308

    https://makecodework.tistory.com/entry/Java-%EB%9E%8C%EB%8B%A4%EC%8B%9DLambda-%EC%9D%B5%ED%9E%88%EA%B8%B0

     

    728x90

    댓글

Designed by Tistory.