JAVA
java.util.function패키지가 제공하는 FunctionalInterface정리
바디스
2023. 2. 9. 14:57
람다식을 사용할 대마다 함수형 인터페이스를 매번 정의하기 불편해서 아예 라이브러리로 제공하는 것들이 있습니다.
자바8에서 제공하는 주요 Funcational 인터페이스는 java.util.function 패키지에 다음과 같이 있습니다.
- Function
- Supplier
- Consumer
- Predicate
- Operators
Function
가장 기본적인 형태로 Object를 입력받고 Object를 리턴하는 매소드 입니다. <T> 는 매개변수의 타입이고, <R> 은 리턴 타입입니다.
호출하는 함수는 apply 입니다.
@FunctionalInterface
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> square = x -> x * x;
System.out.println(square.apply(5)); // Outputs 25
Function
에는 compose
라는 메소드가 있어 메소드를 순서대로 실행시킬 수 있습니다.
Function<Integer, String> intToString = Objects::toString;
Function<String, String> quote = s -> "'" + s + "'";
Function<Integer, String> quoteIntToString = quote.compose(intToString);
System.out.println(quoteIntToString.apply(5)); // '5'
addThen
은 compose
와 반대역할로 현재 메소드를 실행 후 매개변수로 받은 람다를 실행합니다.
Function<String, String> upperCase = v -> v.toUpperCase();
String result = upperCase.andThen(s -> s + "abc").apply("a");
System.out.println(result); // Aabc
identity
는 자신의 값을 그대로 리턴합니다.
String abc = Function.identity().apply("abc");
System.out.println(abc); // abc
Supplier
get() 메서드로 generic으로 선언된 타입을 리턴하는 인터페이스, 단순한 공급자로 추가적인 메서드는 없습니다.
@FunctionalInterface
public interface Supplier<T> {
T get();
}
사용 예시
Supplier<Double> randomNumber = () -> Math.random();
System.out.println(randomNumber.get());
Consumer
Supplier와 반대로 입력은 받지만 리턴하지 않는 인터페이스입니다. accept()매서드로 입력 받은 인수로 작업을 실행합니다.
@FunctionalInterface
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<Integer> print = x -> System.out.println(x);
print.accept(5); // Outputs 5
Predicate
특정 타입의 매개변수를 받아 boolean
값을 리턴하는 인터페이스입니다.
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
사용 예시
Predicate<Integer> isEven = x -> x % 2 == 0;
System.out.println(isEven.test(4)); // Outputs true
System.out.println(isEven.test(5)); // Outputs false
Operators
Operators는 매개변수를 받고 동일한 타입을 리턴하는 인터페이스로 Function을 상속하고 있습니다.
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
static <T> UnaryOperator<T> identity() {
return t -> t;
}
}
사용 예시
UnaryOperator<String> toLower = (s)-> s.toLowerCase();
System.out.println(toLower.apply("Hello World")); // "hello world"
그외의 함수들
매개변수에 따라 구분해서 사용 할 수 있습니다.
Supplier, Consumer, Predicate
- 앞에 Int, Long, Double 등을 붙여서 사용합니다.
IntSupplier
LongSupplier
DoubleSupplier
IntConsumer
LongConsumer
DoubleConsumer
intPredicate
DoublePredicate
LongPredicate
Function의 경우
- 리턴타입을 제니릭으로 받는 경우 앞에 Int, Long, Doulbe을 붙이고
- 매개변수 타입을 제네릭으로 받는 경우 이걸로 리턴한다는 뜻이 To를 추가하여 ToInt, ToLong, ToDouble을 붙입니다.
IntFunction
LongFunction
DoubleFunction
ToIntFunction
ToLongFunction
ToDoubleFunction
매개변수가 두개인 Bi 버전도 있습니다.
BiConsumer
BiFunction
BinaryOperator
BiPredicate
ObjIntConsumer
ObjLongConsumer
ObjDoubleConsumer