람다식, 메서드참조
(매개변수) -> 함수바디(구현부)
interface 변수 = 람다식(함수구현); ex ) MyFunction f1 = () ->System.out.println(“출력”);
- 객체지향언어인 자바를 함수형 언어로 사용
- 익명 함수 (반환타입 X, 메서드 이름 X)
- 익명 클래스의 객체임 (람다식으로 만들때 익명 클래스, 인터페이스 모두 생략)
- 람다식(함수)에서 로컬변수(람다식을 쓰고있는 메서드에 정의된 변수)를 쓰고 싶으면 final로 설정해야 함 (but, default값이 final) -> 메서드 안의 메서드에서 사용하려면 outer 메서드에서 그 변수를 final로 설정해야 함.
하지만, 계산하고 싶으면 바깥메서드의 로컬변수가 아닌 class 영역에 멤버변수로 설정(∵멤버변수는 사용 가능)
▷ 익명클래스 -> 람다식
LambdaInterface f1 = new LambdaInterface() {
@Override
public void method() {
System.out.println("출력");
}
};
↓
LambdaInterface f1 = () -> {
System.out.println("출력");
};
▷ 로컬변수
class Outer {
int iv = 10; // iv
void method() {
int iv = 40; // lv (기본값 : final)
LambdaInterface f = () -> {
// int iv = 50; // 같은 local안에 iv 중복 X
// iv = 50; // final이라 수정 X
System.out.println(Outer.this.iv); //10
System.out.println(this.iv); //10
System.out.println(iv); //40
};
f.method();
}
}
- 메서드[method()] 내의 내부클래스(인터페이스)[LambdaInterface]의 메서드가 람다식으로 구현
- 안의 메서드[람다식-익명함수]에서 바깥메서드[method()]의 변수[iv = 40]를 사용하려면 final로 설정해야함.
람다식 생략 방법
- 매개변수의 타입도 생략가능
- { }안에 문장이 한 줄일 때 { }생략가능 (단, return문 일때는 { return }; 생략)
-> 문장이 아닌 식일경우 { return ;} 생략 가능 - 매개변수가 하나일 때 ( ) 생략가능
● 함수형 인터페이스(@functionalInterface) - 람다식을 다루기 위한 인터페이스, 단 하나의 추상메서드만 선언되어 있음 - 구현시 그 하나의 메서드를 구현하는 것임 (람다식과 인터페이스의 메서드가 1:1 연결) - 일반 인터페이스처럼 디폴트 메서드와 static 메서드도 갖을 수 있음(추상메서드만 하나면 됨)
@FunctionalInterface
interface MyFunction {
void print();
}
public class lambdaEx {
public static void main(String[] args) {
MyFunction f1 = () -> System.out.println("출력"); // 구현
f1.print(); // 실행
}
}
function 패키지 : 함수형 인터페이스를 미리 구현
1. 매개변수나 반환값이 1개이하 함수형 인터페이스
함수형 인터페이스 | 메서드 | 매개변수 | 리턴값 |
java.lang.Runnable | void run() | . | . |
Supplier<.T> | T get() | . |
|
Cousumer<.T> | void accept(T t) |
|
. |
Function<T, R> | R apply(T t) | <.T> |
|
Predicate<.T> | boolean test(T t) |
|
(Boolean) |
UnaryOperator |
T apply(T t) |
|
|
- Function 인터페이스 : 주로 매개값(T)을 리턴값(R)으로 매핑(타입변환)할 경우 사용
- Predicate 인터페이스 : Function의 변형, Boolean값을 반환
- Operator 인터페이스 : Function의 변형, 매개변수타입과 리턴값의 타입이 같음.
2. 매개변수가 2개인 함수형 인터페이스
함수형 인터페이스 | 메서드 | 매개변수 | 리턴값 |
BiCousumer<T, U> | void accept(T t, U u) | <T, U> | . |
BiFunction<T, U, R> | R apply(T t, U u) | <T, U> |
|
BiPredicate<T, U> | boolean test(T t, U u) | <T, U> | (Boolean) |
BinaryOperator<T, T> | T apply(T t, T t) | <T, T> |
|
Consumer<String> c = (t) -> System.out.println(t+8);
↓
Consumer<T> c = new Consumer() {
void accept(T t) {
System.out.println(t+8);
}
};
=======================================1===============================
printString(t -> t.getName());
↓
Function<Student, String> f = t -> t.getName();
printString(f);
↓
Function<Student, String> f = new Function<Student, String>() {
@Override
public String apply(Student t) {
return t.getName();
}
};
printString(f);
=======================================2===============================
printString(t -> t.getName());
↓
printString(new Function<Student, String>() {
@Override
public String apply(Student t) {
return t.getName();
}
});
private static void printString(Function<Student, String> f) {
System.out.println(f.apply(t));
}
● andThen(), compose()
- Function 인터페이스의 default 메서드
- 두개의 함수식 인터페이스를 순차적으로 연결해 실행, 첫번째 리턴 값을 두번째 매개값으로 이용하여 최종값 도출.
- andThen() : 앞→뒤 ex) f1<T, R>.andthen(f2<R, V>) == T,R -> R,V [최종 V리턴타입] (f1 -> f2)
- compose() : 앞←뒤 ex) f1<T, R>.compose(f2<V, T>) == V,T -> T,R [최종 R리턴타입] (f2 -> f1)
● and(), or(), negate()
- Predicate 인터페이스의 default 메서드
- and() : && 대응 -> 두 Predicate가 모두 true면 최종 true 리턴 ex) p12 = p1.and(p2);
- or() : || 대응 -> 두 Predicate 중 하나만 true면 최종 true 리턴 ex) p12 = p1.or(p2);
- negate() : ! 대응-> Predicate 결과가 true이면 false, false이면 true ex) p12 = p1.negate();
메서드 참조
- 람다식에서 불필요한 매개변수를 제거하는 목적 (함수형 인터페이스의 타입을 보고 매개변수의 타입을 충분히 알아 낼 수 있음)
- 함수형 인터페이스와 사용할 메소드의 매개변수 갯수와 타입이 같아야만 사용 가능. 제너릭 참조인 경우에만 사용 가능
static 메서드 참조
IntBinaryOperator operator = (x, y) -> Calculator.staticMethod(x, y);
↓
operator = Calculator::staticMethod;
인스턴스 메서드 참조
Calculator obj = new Calculator();
operator = (x, y) -> obj.instanceMethod(x, y);
↓
operator = obj::instanceMethod;
매개변수의 메서드 참조 (a의 타입 :: 메서드)
ToIntBiFunction<T, U> function = T :: int compareToIgnoreCase(U);
ToIntBiFunction<String, String> function = (a,b) -> a.compareToIgnoreCase(b);
↓
function = String :: compareToIgnoreCase;
생성자와 배열
// 생성자
Function<Integer, Myclass> f = (i) -> new MyClass(i);
↓
Function<Integer, Myclass> f = MyClass::new;
// 배열
Function<Integer, int[]> f = x -> new int[x];
↓
Function<Integer, int[]> f = int[]::new;