람다식은(lamda expression)은 간단히 말해서
메서드를 하나의 식'(exepresseion)으로 표현 한 것입니다.
람다식은 함수를 간략하면서도 명확하게 표현할 수 있게 해줍니다.
int[] arr = new int[5];
Arrays.setAll(arr, (i) -> (int)(Math.random()*5) + 1);
위의 문장에서 '(i) -> (int)(Math.random()*5)+1' 이 바로 람다식이다.
이 람다식이 하는 일을 메서드로 표현하면 다음과 같습니다.
int method(int i){
return (int)(Math.random()*5) + 1 ;
}
메서드보다 람다식이 간결하면서도 이해하기 쉽다.
자바에서 모든 메서드는 클래스에포함되어야 하므로 클래스도 새로 만들고, 객체도 생성해야 비로소 이 메서드를 호출 할 수 있다.
그러나 람다식은 이 모든 과정없이 오직 람다식 자체만으로도 이 메서드의 역할을 대신할 수 있습니다.
int max(int a, int b){
return a > b ? a : b ;
}
메서드를 람다식으로 만드는 방법은 간단합니다.
메서드에서 이름(max)과 반환타입(int)을 제거하고
매개변수 선언부와 몸통 사이에 '->' 만 추가하면 됩니다.
(int a, int b) -> {
return a > b ? a : b ;
}
반환값이 있다면,
return 대신에 'expression(식)' 으로 대신 할 수 있습니다.
식의 연산결과가 자동적으로 반환값이 됩니다.
이 떄는 문장(statement)가 아닌 식 이므로 끝에 ';'는 생략합니다.
(int a, int b) -> a > b ? a : b
람다식에 선언되 매개변수의 타입또한 추론이 가능한 경우 생략 가능합니다.
(대부분의 경우 그렇습니다.)
람다식에 반환 타입이 없는 이유도 항상 추론가능하기 때문입니다.
(a, b) -> a > b ? a : b
만약 선언된 매개변수가 하나 뿐인 경우 괄호도 생략 할 수 있습니다.
단, 매개 변수 타입이 있담녀 괄호를 생략할 수 없습니다.
(a) -> a * a
(int a) -> a * a
a -> a * a // OK
int a - > a * a // Error
마찬가지로 괄호{} 안의 문장이 하나 일 때는
(String name, int i) -> { System.out.println(name + "=" + i }
다음과 같이 괄호를 생략할 수 있습니다.
```java
(String name, int i) -> System.out.println(name + "=" + i)
그러나 괄호안의 문장이 return문일 경우 괄호를 생략할 수 없습니다.
```java
(int a, int b) -> { return a > b ? a : b ;} // OK
(int a, int b) -> return a > b ? a : b // Error
자바에서 모든 메서드는 클래스 내에 포함되어야 합니다.
하ㅁ다식은 어떤 클래스에 포함 되어 있을까요?
지금까지 람다식이 메서드와 동등한 것 같이 설명했지만
사실 람다식은 익명 클래스의 객체와 동등합니다.
예를 들어,
(int a, int b) -> a > b ? a : b
이 람다식은 메서드 이름을 max로 임의로 붙인 다음 객체와 동일하다고 볼 수 있습니다.
new Object() {
int max(int a , int b){
return a > b ? a : b
}
}
호출 하려면 참조변수가 존재 해야 객체의 메서드를 호출 할 수 있으니
일단 이 익명의 객체 주소를 f 라는 참조 변수에 저장해봅니다.
// 참조변수의 타입은 무엇으로 해야 할까???
타입 f = (int a, int b) -> a > b ? a : b ;
참조변수 f 의 타입은 어떤 것이어야 할까요?
인터페이스나 클래스를 통해서 가능합니다.
그 중에서 인터페이스에 대해서 더 자세히 알아봅니다.
아래와 같이 매써드 max가 선언되 MyFunction인터페이스가 정의되어 있다고 해보면,
interface MyFunction {
public abstract int max(int a, int b);
}
이 인터페이스를 구현한 익명 클래스의 객체는 다음과 같이 생성할 수 있습니다.
MyFunction f = new MyFunction(){
public int max(int a, int b){
return a > b ? a : b ;
}
};
int big = f.max(5, 3); // 익명객체의 메서드 호출
MyFuction 인터페이스에 정으된 메서드 max()는 람다식으로
'(int a, int b) -> a > b ? a : b '와 메서드의 선언부와 일치합니다.
따라서,
//익명 객체를 람다식으로 대체
MyFunction f = (int a, int b) -> a > b ? a :b ;
//익명 객체의 메서드 호출
int big = f.max(5, 3);
이와 같이 인터페이스를 통해서 람다식을 다룬다면
기존의 자바의 규칙들을 어기지 않으면서도 자연스럽습니다.
람다식을 다루기 위한 인터페이스를 함수형 인터페이스 (Functional interface)라고 부릅니다. 람다식과 인터페이스의 메서드가 1:1로 연결 되기위해서 '오직 하나의 추상 메서드만' 정의되어 있어야한다는 제약이 있습니다.
@FunctionalInterface
interface Myfunction { // 함수형 인터페이스 MyFunction을 정의
public abstract int max(int a, int b);
}
@FunctionalInterface
interface MyFunction {
void myMethod(); // 추상메써드
}
메서드의 매개변수가 MyFunction타입이면, 이 메서드를 호출할 때 람다식을 참조하는 참조 변수를 매개변수로 지정해야 한다는 뜻 입니다.
void eMethod(MyFunction f) { //매개변수 타입 = 함수형 인터페이스
f.myMethod(); // MyFunction에 정의된 메서드 호출
}
@FunctonalInterface
interface MyFunction {
void run() ; // public abstract void run();
}
Class Ex14_1 {
//매개변수 타입이 MyFunction인 메서드
static void execute(MyFunction f){
f.run();
}
//반환 타입이 MyFunction인 메써드
static MyFunction getMyFunction(){
MyFunction f = () -> System.out.println("f3.run()");
return f;
}
public static void main(String[] args){
//람다식을 MyFunction의 run()을 구현
MyFunction f1 = () -> System.out.println("f1.run()");
//익명의 클래스로 run구현
MyFunction f2 = new Myfunction() {
//public 을 반드시 붙여야함
public void run(){
System.out.println("f2.run*()");
}
MyFunction f3 = getMyFunction();
f1.run();
f2.run();
f3.run();
execute(f1);
execute( () -> System.out.println("run()") );
}
}
--- output ---
f1.run()
f2.run()
f3.run()
f1.run()
run()
--- --- --- ---
대부분 메서드는 타입이 비슷합니다.
매개변수가 0,1,2개
반환값은 0 또는 ₩개
게다가 지네릭 메서드로 저의하면 매개변수나 반환 타입이 달라도 문제가 되지 않습니다.
그래서 java.util.fuction패키지에
일반적으로 자주 쓰이는 형식의 메서드를 함수형 인터페이스로 미리 정해두었습니다.
매번 새로운 함수형 인터페이스를 정의하지 말고, 가능하면
이 패키지의 인터페이스를 활용하는 것이 좋습니다.
그래야 함수영 인터페이스에 정의된 메서드 이름도 통일되고,
재사용성이나 유지보수 측면에서도 좋습니다.
Predecate<T> Example.
Predicate<String> inEmptyStr = s -> s.length() == 0;
String s = "" ;
if(inEmptyStr.test(s))
System.out.println("This is am empty String");
매개변수가 두개인 함수형 인터페이스
매개변수 타입과 반환 타입이 일치하는 인터페이스
여러 조건식을 논리 연산자인