람다식
: 익명 함수를 생성하기 위한 식, 함수에 가까움
매개변수가 하나일 경우 소괄호 생략 가능, 람다식 내 코드가 한 줄일 경우 중괄호 생략 가능
return문만 있을 때는 중괄호 생략 불가
// (타입 매개변수1, 매개변수2, ...) -> { ... }
// 혹은
// (매개변수1, 매개변수2, ...) -> { ... }
// 람다식 예시
(int a) -> { sout(a); };
- 람다식에서의 메소드 매개변수 또는 로컬 변수는 final 특성을 가짐
: 수정 불가
함수적 인터페이스(@FunctionalInterface)
: 하나의 추상 메소드가 선언된 인터페이스를 람다식을 이용하여 구현 객체를 생성하고자 할 때 사용
인터페이스 상단에 @FunctionalInterface 어노테이션을 붙여서 사용
// 인터페이스 선언
@FunctionalInterface
public interface MyFunctionalInterface {
public void method();
}
// 함수적 인터페이스 사용
MyFunctionalInterface fi = () -> { ... };
람다식 내에서 로컬 변수 사용
- 람다식 내에서 this 사용시 람다식 내부를 의미
- 람다식 바깥 객체를 참조하려면 클래스명.this.객체명으로 접근
표준 API의 함수적 인터페이스
: 자바에서 제공되는 표준 API 중, 하나의 추상 메소드를 가지는 인터페이스들은 모두 람다식을 이용하여 익명 구현 객체로 표현 가능
ex) Runnable
- 예시
public static void main(String[] args) {
Runnable runnable = () -> {
for(int i = 0; i < 10; i++) {
System.out.println(i);
}
};
Thread thread = new Thread(runnable);
thread.start();
// 또는
Thread thread2 = new Thread(() -> {
for(int i = 0; i < 10; i++) {
System.out.println(i);
}
});
}
함수적 인터페이스 표준 패키지
종류 | 특징 |
Consumer | 매개값은 있고 리턴값은 없음 |
Supplier | 매개값은 없고 리턴값은 있음 |
Function | 매개값은 있고 리턴값도 있음 주로 매개값을 리턴값으로 매핑(타입 변환) |
Operator | 매개값은 있고 리턴값도 있음 주로 매개값을 연산하고 결과를 리턴 |
Predicate | 매개값은 있고 리턴값은 boolean 타입 매개값을 조사하여 true or false 반환 |
1. Consumer 함수적 인터페이스
: 리턴값이 없는 accept() 메소드를 가짐 → 해당 메소드로 Consumer 실행
// consumer 예시
Consumer<String> consumer = t -> { ... };
consumer.accept("java");
BiConsumer<String> consumer2 = (t, u) -> { ... };
DoubleConsumer<String> consumer3 = d -> { ... };
ObjIntConsumer<String> consumer4 = (t, i) -> { ... };
2. Supplier 함수적 인터페이스
: 매개변수가 없고 리턴값이 있는 getXXX() 메소드를 가짐 → get(), getAsInt() 등
// supplier 예시
Supplier<String> supplier = () -> { ... return ""; };
sout(supplier.get());
IntSupplier<String> supplier2 = () -> { ... return 1; };
sout(supplier2.getAsInt());
3. Function 함수적 인터페이스
: 매개값과 리턴값이 있는 applyXXX() 메소드를 가짐
// function 예시
private static List<Student> list = Arrays.asList(
new Student("홍길동", 90, 96),
new Student("신용권", 95, 93)
);
public static double avg(ToIntFunction<Student> function) {
int sum = 0;
for(Student student : list) {
sum += function.applyAsInt(student);
}
double avg = (double) sum / list.size();
return avg;
}
public static void main(String[] args) {
double englishAvg = avg(s -> s.getEnglishScore());
System.out.println("영어 평균 점수: " + englishAvg);
double mathAvg = avg(s -> s.getMathScore());
System.out.println("수학 평균 점수: " + mathAvg);
}
4. Operator 함수적 인터페이스
: Function과 동일하지만 Function과는 다르게 매개값을 리턴값으로 매핑하는 역할보다는 매개값을 이용하여 연산을 수행하여 그 값을 동일한 타입으로 리턴 → applyXXX() 메소드를 가짐
5. Predicate 함수적 인터페이스
: 매개 변수와 boolean 리턴값이 있는 testXXX() 메소드를 가짐, true/false 리턴
Predicate, BiPredicate, DoublePredicate, IntPredicate, LongPredicate 등이 있음
// predicate 예시
Predicate<Student> predicate = t -> { return t.getSex().equals("남자"); }
// 또는
Predicate<Student> predicate = t -> t.getSex().equals("남자");
andThen()과 compose() 디폴트 메소드
: 함수적 인터페이스가 가지고 있는 디폴트 메소드
두 개의 함수적 인터페이스를 연결하고, 첫 번째 처리 결과를 두 번째 매개값으로 제공
1. andThen()
: 인터페이스 A부터 처리하고 결과를 인터페이스 B의 매개값으로 제공 → 인터페이스 B의 최종 결과 리턴
Consumer, Function, Operator 함수적 인터페이스에서 사용 가능
// andThen 예시
// 1. Consumer는 리턴 결과를 제공하지 않으므로 순서만 지정
Consumer<Member> consumerAB = consumerA.andThen(consumerB);
// 2. Function이나 Operator는 결과를 제공하므로 객체 형식 유의
Function<Member, Address> functionA;
Function<Address, String> functionB;
...
Function<Member, String> functionAB = functionA.andThen(functionB);
Function<Member, String> functionAB = functionB.compose(functionA); // 같음
2. compose()
: 인터페이스 B부터 처리하고 결과를 인터페이스 A의 매개값으로 제공 → 인터페이스 A의 최종 결과 리턴
Function(BiFunction 불가), Operator(Binary 불가), 함수적 인터페이스에서 사용 가능
and(), or(), negate() 디폴트 메소드와 isEqual() 정적 메소드
: Predicate 함수적 인터페이스에서 사용 가능
논리 연산자 &&, ||, !와 대응
// 1. and
IntPredicate predicateAB = predicateA.and(predicateB);
// 2. or
IntPredicate predicateAB = predicateA.or(predicateB);
// 3. negate
IntPredicate predicateAB = predicateA.negate();
// 4. isEqual
Predicate<String> predicate = Predicate.isEqual(null);
System.out.println(predicate.test(null));
minBy, maxBy 정적 메소드
: BinaryOperator에서 사용 가능
매개값으로 제공되는 Comparator를 이용하여 최대 T와 최소 T를 얻는 BinaryOperator<T> 리턴
// 예시
BinaryOperator<Fruit> binaryOperator = BinaryOperator.minBy( (f1, f2) -> Integer.compare(f1.price, f2.price) );
Fruit friut = binaryOperator.apply(new Fruit("딸기", 6000), new Fruit("수박", 10000)); System.out.println(friut.name);
메소드 참조
메소드를 참조하여 매개변수의 정보 및 리턴 타입을 알아내어 람다식에서 불필요한 매개변수를 제거
- 정적 메소드와 인스턴스 메소드 참조
: 클래스 이름 뒤에 :: 기호를 붙임
정적 메소드는 클래스::메소드, 인스턴스 메소드는 참조변수::메소드 형태로 사용
// 정적 메소드와 인스턴스 메소드 참조 예시
IntBinaryOperator operator = (x, y) -> Calculator.staticMethod(x, y);
// 또는
IntBinaryOperator operator = Calculator::staticMethod;
- 매개변수의 메소드 참조
: 정적 메소드와 같이 클래스::메소드 형태로 사용
// 매개변수의 메소드 참조 예시
ToIntBiFunction<String, String> function = (a, b) -> a.compareToIgnoreCase(b);
// 또는
ToIntBiFunction<String, String> function = String::compareToIgnoreCase;
- 생성자 참조
: 객체 생성을 의미
클래스::new 형태로 사용
// 생성자 참조 예시
Function<String, Member> function1 = Member::new;
Member member1 = function1.apply("angel");
'Language > Java' 카테고리의 다른 글
Java - 제네릭 (0) | 2021.07.07 |
---|---|
Java - 멀티 스레드 정리 (0) | 2021.07.02 |
Java - 기본 API 클래스 정리 (0) | 2021.06.25 |
Java - 중첩 클래스와 중첩 인터페이스, 예외 처리 복습 (0) | 2021.06.25 |
Java - 인터페이스 복습 (0) | 2021.06.24 |