이 글은 java.util.function 패키지의 함수형 인터페이스 표준 API에 대해서 설명합니다.
학습 목표
· java.util.function 패키지
· Consumer
· Supplier
· Function
· Operator
· Predicate
java.util.function 패키지
자바에서 제공되는 표준API에서 한 개의 추상 메소드를 가지는 인터페이스들은 모두 람다식을 이용해서 익명 객체로 표현 가능하다.
예를 들어 스레드의 작업을 정의하는 Runnable 인터페이스는 매개 변수와 리턴값이 없는 run() 메소드만 존재하므로 람다식을 이용해서 Runnable 인터페이스를 생성할 수 있다.
Runnable runnable = ()-> {
System.out.println("스레드 시작");
};
Thread thread = new Thread(runnable);
thread.run();
Thread 생성자를 호출할 때 람다식을 매개값으로 대입해도 된다.
Thread thread = new Thread(() ->{ System.out.println("스레드 시작");});
thread.run();
자바 8부터는 빈번하게 사용되는 함수형 인터페이스는 java.util.function 표준 API 패키지로 제공한다.
java.util.function 패키지의 함수형 인터페이스는 크게 Consumer, Supplier, Function, Operator, Predicate로 구분된다. 구분 기준은 인터페이스에 선언된 추상 메소드의 매개값과 리턴값의 유무다.
|
종류 |
추상메소드 특징 |
|
Consumer |
매개값 o, 리턴값 x |
|
Supplier |
매개값 x, 리턴값 o |
|
Function |
매개값 o, 리턴값 o |
|
Operator |
매개값 o, 리턴값 o |
|
Predicate |
매개값 o, 리턴값 o (boolean 타입으로 한정) |
Consumer
Consumer 함수형 인터페이스은 리턴값이 없는 accept() 메소드를 갖는다. accept()는 단지 매개값을 소비하는 역할을 하고, 리턴 값이 없다.
매개 변수의 타입과 수에 따라 아래와 같은 Consumer들이 있다.
|
인터페이스명 |
추상메소드 |
설명 |
|
Consumer<T> |
void accept(T t) |
객체 T를 받아 소비 |
|
BiConsumer<T> |
void accept(T t, U u) |
객체 T와 U를 받아 소비 |
|
DoubleConsumer<T> |
void accept(double value) |
double 값을 받아 소비 |
|
IntConsumer<T> |
void accept(int value) |
int 값을 받아 소비 |
|
LongConsumer<T> |
void accept(long value) |
long 값을 받아 소비 |
|
ObjDoubleConsumer<T> |
void accept(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 값을 받아 소비 |
예시
public class ConsumerExam {
public static void main(String []args){
Consumer<String> consumer = t -> System.out.println(t + "8");
consumer.accept("Java");
BiConsumer<String, String> bigConsumer = (t, u) -> System.out.println(t+u);
bigConsumer.accept("Java", "8");
DoubleConsumer doubleConsumer = d -> System.out.println("Java" + d);
doubleConsumer.accept(8.0);
ObjIntConsumer<String> objIntConsumer = (t, i) -> System.out.println(t + i);
objIntConsumer.accept("Java",8);
}
}

Supplier
Supplier 함수형 인터페이스는 매개 값이 없고 리턴값이 있는 getXXX() 메소드를 갖는다. 이 메소드는 실행 후 호출한 곳으로 데이터를 공급하는 역할을 한다.
리턴 타입에 따라서 아래와 같은 Supplier 함수형 인터페이스가 있다.
|
인터페이스명 |
추상메소드 |
설명 |
|
Supplier<T> |
T get() |
T 객체를 리턴 |
|
BooleanSupplier |
boolean getAsBoolean() |
boolean 값을 리턴 |
|
DoubleSupplier |
double getAsDouble() |
double 값을 리턴 |
|
IntSupplier |
Int getAsInt() |
int 값을 리턴 |
|
LongSupplier |
long getAsLong() |
long 값을 리턴 |
예시
public class SupplierExam {
public static void main(String []args){
IntSupplier intSupplier = () -> {
int num = (int) (Math.random() * 6) + 1;
return num;
};
int num = intSupplier.getAsInt();
System.out.println("눈의 수: " + num);
}
}

Function
Function 함수형 인터페이스는 매개값과 리턴값이 있는 applyXXX() 메소드를 갖는다. 이 메소드들은 매개값을 리턴값으로 매핑(타입 변환)하는 역할을 한다.
매개 변수 타입과 리턴 타입에 따라서 아래와 같은 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(int value) |
double을 객체 R로 매핑 |
|
IntFunction<R> |
R apply(int value) |
int를 객체 R로 매핑 |
|
IntToDoubleFunction |
double applyAsDouble(int value) |
int를 double로 매핑 |
|
IntToLongFunction<R> |
long applyAsLong(int value) |
int를 long으로 매핑 |
|
LongToDoubleFunction<R> |
double apply(T t) |
long을 double로 매핑 |
|
LongToIntFunction<R> |
int applyAsInt(long value) |
long을 int로 매핑 |
|
ToDoubleBiFunction<T,U> |
double applyAsDouble(T t, U u) |
객체 T와 U를 double로 매핑 |
|
ToDoubleFunction<T> |
double applyAsDouble(T vaule) |
객체 T를 double로 매핑 |
|
ToIntBiFunction<T,U> |
int applyAsInt(T t, U u) |
객체 T와 U를 Int로 매핑 |
|
ToIntFunction<T> |
int applyAsInt(T value) |
객체 T를 Int로 매핑 |
|
ToLongBiFunction<T,U> |
long applyAsLong(T t, U u) |
객체 T와 U를 long으로 매핑 |
|
ToLongFunction<T> |
long applyAsLong(T value) |
객체 T를 long으로 매핑 |
예시
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.ToIntFunction;
public class FunctionExam {
public static void main(String args[]){
List<Student> list = Arrays.asList(
new Student("리누스", 90, 96),
new Student("토발스", 95, 93)
);
System.out.println("학생 이름");
studentStringPrint(list, t -> t.getName());
System.out.println("영어 점수");
studentIntPrint(list, t -> t.getEnglishScore());
System.out.println("수학 점수");
studentIntPrint(list, t -> t.getMathScore());
}
public static void studentIntPrint(List<Student> students,ToIntFunction<Student> function){
for(Student student: students){
System.out.print(function.applyAsInt(student) + " ");
}
System.out.println();
}
public static void studentStringPrint(List<Student> students, Function<Student, String> function){
for(Student student: students){
System.out.print(function.apply(student) + " ");
}
System.out.println();
}
}

Operator
Operator 함수형 인터페이스는 Function과 동일하게 매개 변수와 리턴값이 있는 applyXXX() 메소드를 갖는다.
하지만 이 메소들은 주로 매개값을 이용해서 연산을 수행한 후 동일한 타입으로 리턴값을 제공하는 역할을 한다는 점에서 Function과 다르다.
매개 변수 타입과 수에 따라서 아래와 같은 Operator 함수형 인터페이스가 있다.
|
인터페이스명 |
추상메소드 |
설명 |
|
BinaryOperator<T> |
BiFunction<T,U,R> |
T와 U를 연산한 후 R 리턴 |
|
UnaryOperator<T> |
Function<T,R>의 하위 인터페이스 |
T를 연산한 후 R 리턴 |
|
DoubleBInaryOperator |
double applyAsDouble(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 연산 |
예시
import java.util.function.IntBinaryOperator;
public class OperatorExam {
public static void main(String[] args){
int[] scores = {92, 95, 87};
// 최대값 얻기
int max = maxOrWin(scores,
(a, b) -> {
if(a>=b) return a;
else return b;
});
System.out.println("최대값: " + max);
//최소값 얻기
int min = maxOrWin(scores,
(a,b) -> {
if(a<=b) return a;
else return b;
});
System.out.println("최소값: " + min);
}
public static int maxOrWin(int [] scores, IntBinaryOperator operator){
int result = scores[0];
for(int score : scores){
result = operator.applyAsInt(result, score);
}
return result;
}
}

Predicate
Predicate 함수형 인터페이스는 매개 변수와 boolean 리턴값이 있는 testXXX() 메소드를 가지오 있다. 이 메소드들은 매개값을 조사해서 true 또는 false를 리턴한다.
매개 변수 타입과 수에 따라서 아래와 같은 Predicate 함수형 인터페이스가 있다.
|
인터페이스명 |
추상메소드 |
설명 |
|
Predicate<T> |
boolean test(T t) |
객체 T를 조사 |
|
BiPredicate<T, U> |
boolean test(double value) |
double 값을 조사 |
|
IntPredicate |
boolean test(int value) |
int 값을 조사 |
|
LongPredicate |
boolean test(long value) |
long 값을 조사 |
예시
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class PredicateExam {
public static void main(String[] args){
List<Student> students = Arrays.asList(
new Student("리누스","남자",88),
new Student("토발즈","남자",95),
new Student("안나","여자",95),
new Student("카레니나","여자",92)
);
double maleAvg = avg(students, t-> t.getSex().equals("남자"));
System.out.println("남자 평균 정수: " + maleAvg);
double femaleAvg = avg(students, t->t.getSex().equals("여자"));
System.out.println("여자 평균 점수: " + femaleAvg);
}
public static double avg(List<Student> students, Predicate<Student> predicate){
int count = 0, sum = 0;
for(Student student : students){
if(predicate.test(student)){
count ++;
sum += student.getScore();
}
}
return (double) sum / count;
}
}

'자바' 카테고리의 다른 글
| [Java] 실수 > 정수 (float to int, double to int) 변환하기 (0) | 2021.05.26 |
|---|---|
| [Java] Cipher, 자바의 암호화&복호화를 담당하는 클래스 (2) | 2021.04.20 |
| [Java] 자바의 람다식이란? (0) | 2021.03.06 |
| [Java] List를 Array로 변환하기 (2) | 2021.02.15 |
| [Java] Enum, 자바의 열거타입을 알아보자 (0) | 2021.01.29 |
댓글