람다와 함수형 인터페이스
앞의 람다의 소개에서 봤던 것을 대충 정리하자면
A -> B 가 람다식이라 할 때
-> 는 연산자이고 ->의 왼쪽에 매개변수에 대한 선언정보, 오른쪽에 람다식으로 표현하고자 하는 연산문이 들어오게 된다.
함수형 인터페이스란?
인터페이스 중 구현해야할 추상 메소드가 딱 하나 있는 인터페이스를 가리켜 함수형 인터페이스라고 한다.
우리가 앞의 예시에서 봤듯이
우리가 람다식을 작성하는 대상이 바로 함수형 인터페이스이다.
람다는 인스턴스보다 기능 하나가 필요한 상황을 위하여 있다.
앞에서 보았던
Collections.sort(list, new SLenComp()); // 정렬
과 같이 두번째 인자로 필요한 것은 사실 compare 메소드이나
메소드를 인자로 주는 것이 불가능하기 때문에 인스턴스를 생성하여 두번째 인자로 전달해주게 된다.
이런 경우 람다식이 인스턴스 생성을 대신 하게 될 수 있다.
매개변수가 있고 반환하지 않는 람다식
ex.
interface Printable {
void print(String s); // 매개변수 하나, 반환형 void
}
class OneParamNoReturn {
public static void main(String[] args)
{
Printable p;
p = (String s) -> {System.out.println(s)}; // 줄임없는 표현
p.print("Hello World");
p = (String s) -> System.out.println(s); // 중괄호 생략
p.print("Hello World");
p = (s) -> System.out.println(s); // 매개변수 형 생략
p.print("Hello World");
p = s->System.out.println(s); // 매개변수 소괄호 생략
p.print("Hello World");
}
}
메소드 몸체가 둘 이상의 문장으로 이루어져 있으면 메소드의 표현인지 다른 식인지 확실하게 해주어야 하므로 중괄호의 생략이 불가능하다.
매개변수의 수가 둘 이상인 경우에도 소괄호의 생략이 불가능하다.
즉 일반적으로는
p = (a, b...) -> { ~; ~; ~;};
이와 같은 표현이 맞다.
매개변수가 둘인 람다식의 예시
interface Calculate {
void cal(int a, int b);
}
class TwoParamNoReturn {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> System.out.println(a + b);
c.cal(4, 3);
}
}
매개변수가 있고 반환하는 람다식
interface Calculate {
int cal(int a, int b);
}
class TwoParamAndReturn {
public static void main(String[] args) {
Calculate c;
c = (a, b) -> {return a + b;}; // return문의 중괄호 생략은 불가
System.out.println(c.cal(4,3));
c = (a, b) -> a + b; // 연산 결과가 남으면 별도로 명시하지 않아도 반환대상이 됨
System.out.println(c.cal(4,3));
}
}
return 문을 쓰면 중괄호는 생략 불가능하다.
그냥 return 하는건지 람다식인지 구분이 필요하기도 하고
return문은 문장의 시작 부분에 위치한다는 규칙을 깨지 않는 것이 컴파일러 설계 상 좋기 때문이기도 하다.
그리고 마지막 문장 실행결과 연산 결과가 남으면 return을 명시하지 않아도 그 값을 리턴한다.
매개변수가 없는 람다식
interface Generator {
int rand();
}
class NoParamAndReturn {
public static void main(String[] args) {
Generator gen = () -> {
Random rand = new Random();
return rand.nextInt(50); // 0 ~ 49의 숫자 중 하나 랜덤으로 리턴
}
System.out.println(get.rand());
}
}
함수형 인터페이스(Functional Interface)와 어노테이션
함수형 인터페이스: 추상 메소드가 딱 하나만 존재하는 인터페이스
@FunctionalInterface : 함수형 인터페이스의 조건을 갖추었는지에 대한 검사를 컴파일러에게 요청!
@FunctionalInterface
interface Calculate {
int cal(int a, int b);
}
@FunctionalInterface
interface Calculate {
int cal(int a, b);
default int add(int a, int b) {return a + b;}
static int sub(int a, int b) {return a - b:}
}
위의 두 인터페이스는 모두 함수형 인터페이스의 조건을 갖추었다.
둘 다 추상 메소드가 하나이기 때문이다.
람다식과 제네릭
@FunctionalInterface
interface Calculate <T> {
T cal(T a, T b);
}
class LambdaGeneric {
public static void main(String[] args) {
Calculate<Integer> ci = (a, b) -> a + b;
System.out.println(ci.cal(4, 3));
}
}
인터페이스가 제네릭 기반이라 하여 특별히 신경쓸 필요는 없다.
타입인자가 전달이 되면 추상 메소드의 T는 결정이 되므로!
(https://honeyricecake-webdev.tistory.com/29 의 4.다이아몬드 기호를 참고하자.)