함수형 인터페이스, java.util.function 패키지
함수형 인터페이스 : 1개의 추상 메서드를 갖고 있는 인터페이스를 말한다. SAM라고도 불린다.
함수형 인터페이스는 자바의 람다식은 함수형 인터페이스로만 접근이 되기 때문이다.
public interface FunctionalInterface {
public abstract void doSomething(String text);
}
FunctionalInterface func = text -> System.out.println(text); // 이와 같이 재정의하고
func.doSomething("do something"); // 이와 같이 함수를 호출한다.
즉 함수형 인터페이스는 람다식으로 만든 객체에 접근하기 위해서이다.
익명클래스를 사용하면 아래와 같다.
FunctionalInterface func = new FunctionalInterface() {
@Override
public void doSomething(String text) {
System.out.println(text);
}
};
func.doSomething("do something");
익명클래스를 더 간단하게 표현하기 위한것이라고 봐도 무방하다.
람다식을 사용할 대마다 함수형 인터페이스를 매번 정의하기 불편해서 아예 라이브러리로 제공하는 것들이 있다.
자바8에서 제공하는 주요 Funcational 인터페이스는 java.util.function 패키지에 다음과 같이 있다.
- Predicate
- Supplier
- Consumer
- Function
- UnaryOperator
- BinaryOperator
Predicate
@FunctionalInterface
public interface Predicate<T>
* Represents a predicate (boolean-valued function) of one argument.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #test(Object)}.
*
Predicate<String> predicateLengths = (a) -> a.length() > 5;
test()라는 메서드가 있고 두개의 객체를 비교할 때 사용하고 boolean을 리턴한다.
추가로 and(), negate() or()이라는 디폴트 메소드가 구현되어 있고, isEqual()이라는 static 메소드도 존재함.
Supplier
get() 메서드가 있어, 리턴값은 generic으로 선언된 타입을 리턴함, 다른 인터페이스들과는 다르게 추가적인 메서드는 선언되어 있지 않음.
public interface Supplier<T> {
T get();
}
Supplier<String> getString = () -> "Happy new year!";
String str = getString.get();
System.out.println(str);
// 결과
// Happy new year!
Consumer
accept()라는 매개 변수를 갖는 메서드가 있으며 리턴값이 없다, 그래서 출력을 할 때 작업을 수행하고 결과를 받을 일이 없을 때 사용.
추가로 andThen() 이라는 디폴트 메소드가 구현되어 있는데 순차적인 작업 처리할 때 유용.
(consume, 그냥 결과값을 반환하지 않고 삼킨다고 기억)
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
Consumer<String> printString = text -> System.out.println("Miss " + text + "?");
printString.accept("me");
// 결과
// Miss me?
Function
apply()라는 하나의 매개변수를 갖는 메서드가 있으며, 리턴값도 존재함. 이 인터페이스는 Function<T,R>로 정으되어 있어, Generic 타입을 두개 갖고 있다.
앞에 있는 T는 입력 타입, 뒤에 있는 R은 리턴타입을 의미한다.
즉 변환을 할 필요가 있을 때 이 인터페이스를 사용한다.
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
Function<Integer, Integer> multiply = (value) -> value * 2;
Integer result = multiply.apply(3);
System.out.println(result);
// 결과
// 6
UnaryOperator
apply()라는 하나의 매개변수를 갖는 메서드가 있으며, 리턴값도 존재한다. 단, 한가지 타입에 대해 결과도 같은 타입일 경우 사용.
아래와 같이 사용됨
UnaryOperator<String> toLower = (s)-> s.toLowerCase();
System.out.println(toLower.apply("Hello World"));
BinaryOperator
apply() 라는 두개의 매개 변수를 갖는 메소드가 있으며, 리턴값도 존재한다. 단 한가지 타입에 대해서 결과도 같은 타입일 경우 사용한다.
- BinaryOperator는 인수 2 개를 받아, 인수와 같은 타입의 값을 리턴하는 함수를 의미한다.
- 입력 인수와 반환값의 타입이 같다.
- 두 인수는 타입이 같아야 한다.
BinaryOperator<Integer> add = (a, b) -> a + b;
System.out.println(add.apply(1, 2));