이 글은 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 |
댓글