함수적 인터페이스
자바 8부터 java.util.function 표준 API로 함수적 인터페이스가 제공되기 시작했습니다.
2022.01.20 - [Language/Java] - [Java/자바] 람다식(Lambda Expression), 함수형 인터페이스 사용법
위 글과 같이 함수형 인터페이스를 매번 선언하고 구현하는 불편함을 덜어주기 위해 제공된 함수적 인터페이스는
모두 interface로 구성되어 있고 제네릭을 사용하여 일관성 있고 편리한 함수형 프로그래밍이 가능케 합니다.
대표적인 인터페이스는 다음과 같습니다.
인터페이스 명 | 매개 변수 유무 | 리턴 유무 | 메소드 |
Consumer | O | X | accept(T t) |
Supplier | X | O | get() |
Function | O | O | apply(T t) |
Operator | O | O | - |
Predicate | O | O(boolean) | test(T t) |
그럼 종류별로 사용 방법을 알아보겠습니다.
1. Consumer - accpet()
Consumer 인터페이스는 파라미터를 받아 소비하지만 리턴은 없는 void 메소드입니다.
accept() 추상 메소드를 람다식으로 구현하고 객체.accept(파라미터) 메소드를 통해 실행시킵니다.
Consumer<String> consumer = System.out::println; // s -> System.out.println(s) 동일한 결과
consumer.accept("hello");
BiConsumer<Integer, Integer> consumer2 = (i1, i2) -> System.out.println(i1+", "+i2);
consumer2.accept(1,2);
첫번째 객체는 하나의 파라미터를 받는 Consumer,
두번째 객체는 두 개의 파라미터를 받는 BiConsumer 인터페이스를 통해 구현했습니다.
위쪽 표에 있는 다른 메소드들을 보면 같은 방식이지만 정해진 타입의 파라미터만 받기 때문에 제네릭 선언이 필요 없는 것도 있습니다.
대충 이름만 보고도 어떠한 타입이 들어갈지 다들 예상될거라 생각합니다.
2. Supplier - get()
Supplier 인터페이스는 매개 변수를 갖지 않고 값만 반환하기 때문에
람다 실행식 안에서 변수를 정의한 후 값을 리턴하도록 해야합니다.
Supplier 인터페이스의 추상 메소드는 get###() 형식으로 통일되어 있습니다.
제네릭으로 직접 타입을 명시하면 그냥 get() 메소드,
타입이 정해진 메소드는 getAsType()을 정의하고 사용하시면 됩니다.
Supplier<String> supplier = () -> "hello!";
System.out.println(supplier.get());
Scanner sc = new Scanner(System.in);
IntSupplier intSupplier = () -> sc.nextInt();
System.out.println(intSupplier.getAsInt());
첫번째 객체는 문자열을 반환해줘서 출력을 해주었고,
두번째 객체는 Scanner로 숫자 10을 입력받아 반환해주었습니다.
3. Function - apply()
Function 인터페이스는 파라미터를 받아, 다른 타입의 값으로 매핑(타입 변환)합니다.
추상 메소드는 공통적으로 apply###() 형식으로 통일되어있습니다.
Function 인터페이스를 사용해 Integer에서 String으로 타입 변환하는 간단한 예제를 보겠습니다.
Function<String, Integer> sToInt = s -> Integer.parseInt(s);
System.out.println(sToInt.apply("5") + sToInt.apply("10"));
String에서 Integer로 변환되었기 때문에 출력에서 문자열 510이 아닌 두 수의 합인 15가 출력되었습니다.
4. Operator
인터페이스명 | 추상 메소드 | 설명 |
BinaryOperator<T> | T apply(T t T t) | T와 T를 연산한 후 T 리턴 |
UnaryOperator<T> | T apply(T t) | 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 연산 |
Operator 인터페이스의 추상 메소드는 Function과 동일하게 매개 변수와 리턴값이 있는 apply()를 지닙니다.
그 이유는 Function의 특성을 상속받았기 때문인데요.
그만큼 비슷한 사용 방법을 가지고 있지만 Operator 메소드들은 매개값을 리턴값으로 매핑하는 역할보다는
매개 값을 이용해 연산을 수행한 후 동일한 타입으로 리턴 값을 제공한다는 차이가 있습니다.
그럼 최대 값을 구하는 예제로 간단하게 알아보겠습니다.
private static int[] scores = {1, 20, 300};
public static void main(String[] args) {
int max = maxOrMin( (a,b) -> (a>=b) ? a : b );
System.out.println("최대값 : "+max);
}
public static int maxOrMin(IntBinaryOperator op) {
int result = scores[0];
for(int i : scores) {
result = op.applyAsInt(result, i); // applyAsInt(int, int)
}
return result;
}
maxOrMin() 메소드에서 두 수를 비교하는 연산을
IntBinaryOperator 인터페이스의 추상 메소드 applyAsInt(int, int) 를 이용했습니다.
메인 문에서는 람다식을 통해 추상 메소드를 큰 수가 리턴 되도록 구현해주었습니다.
5. 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() 추상 메소드를 지니고 있습니다.
그럼 컴공과 학생의 이름을 출력하는 간단한 예시를 보겠습니다.
HashMap<String, String> student = new HashMap<>() {
{ put("A", "컴공"); put("B", "경영"); put("C", "컴공"); }
};
Predicate<String> isCom = major -> major.equals("컴공");
for(String key : student.keySet()) {
if(isCom.test(student.get(key))) // test 메소드
System.out.println(key+"는 컴공과입니다.");
}
해시맵으로 키에는 이름을 넣어주고 값에는 학과를 넣었습니다.
Predicate 인터페이스 구현할 객체를 생성한 후 람다식에 equals() 메소드를 통해
String 값의 매개 변수가 "컴공"이면 true 아니면 false를 리턴하도록 하였습니다.
if문에서는 추상 메소드 test()를 통해 매개 변수로 학과를 넣어주어 true, false를 리턴받고 출력을 실행시키도록 했습니다.
결과는 컴공과인 A와 C가 정상적으로 출력되는 모습입니다.
이번 함수적 인터페이스를 배울 때 너무 빠르게 진도를 나가다보니 인터페이스는 너무나 많고
각각 인터페이스에 대한 메소드도 너무 많다보니 정신을 못차렸는데,
한번 크게 정리를 하며 인터페이스와 각 추상 메소드들에 대한 정보가 눈에 익다보니 할만 하다는 생각이 듭니다.
그리고 함께 사용하는 람다식은 처음 배울 때 사전 정보가 없으면 많이 어려움을 느끼지만
하나씩 쌓이고 나면 정말 매력적인것 같네요.
자바 함수적 인터페이스 사용법, Consumer 함수적 인터페이스 사용법, Supplier 함수적 인터페이스 사용법, Function 함수적 인터페이스 사용법, Operator 함수적 인터페이스 사용법, Predicate 함수적 인터페이스 사용법
'Java, JSP' 카테고리의 다른 글
[Java/자바] 메소드 참조(method reference), "::" 사용법 (0) | 2022.01.27 |
---|---|
[Java/자바] 스트림(Stream) 사용법 (0) | 2022.01.25 |
[Java/자바] 람다식(Lambda Expression), 함수형 인터페이스 사용법 (0) | 2022.01.20 |
[Java/자바] 쓰레드/Thread 사용법 (상속, Runnable) (0) | 2022.01.19 |
[Java/자바] FileInputStream, FileReader, 파일 불러오기 (0) | 2022.01.14 |
댓글