람다 표현식(lambda Expression)
▤ 목차
✔ 람다 표현식
java SE 8부터 나온 람다 표현식은 메서드를 하나의 식으로 표현한 것을 말한다.
하나의 추상 메서드를 가지고 있는 인터페이스를 가지고 있어야 사용이 가능하다.
무명 클래스를 화살표 기호를 사용하여 짧게 줄일 수 있다.
(parameter ,,,) -> { body }
만약, 람다식이 하나의 메서드를 호출하는 경우 ::으로 표현할 수 있다.
1) 클래스 이름 :: 메서드 이름
2) 참조변수 :: 메서드 이름
가독성이 좋은 쪽으로 선택하자.
💻 코드로 보기
interface HelloInter {
int calcData(int a, int b);
}
public class MyLambda1 implements HelloInter {
@Override
public int calcData(int a, int b) {
return a + b;
}
public static void main(String[] args) {
System.out.println(my.calcData(3, 4));
}
}
interface HelloInter {
int calcData(int a, int b);
}
public class MyLambda1 implements HelloInter {
public static void main(String[] args) {
HelloInter inter = (x, y) -> x + y;
System.out.println("두 수를 더한 결과 : "+inter.calcDate(4,6));
}
}
클래스를 작성하고 객체를 생성하지 않아도 메서드를 사용할 수 있다.
자바에서는 클래스의 선언과 동시에 객체를 생성하므로, 단 하나의 객체만을 생성할 수 있는 클래스를 익명클래스라고 한다.
람다 표현식을 사용하면, 불필요한 코드를 줄여주고 가독성을 높여준다.
👏 정리
- 매개변수가 하나인 경우 괄호()를 생략할 수 있다.
- 매개변수 타입을 추론할 수 있는 경우, 타입을 생략할 수 있다.
- body에 문장이 1개이면 중괄호{}를 생략할 수 있다.
- body에 return문 1개인 경우 중괄호{} 생략이 가능하다.
📝 인터페이스에 추상 메서드가 2개있다면?
interface HelloInter {
int calcData(int a, int b);
int calcData2(int a, int b);
}
public class MyLambda1 implements HelloInter {
@Override
public int calcData(int a, int b) {
// 인터페이스의 추상 메서드를 오버라이딩 : 전통적인 방법
return a + b;
}
//
// @Override
// public int calcData2(int a, int b) {
// return 0;
// }
public static void main(String[] args) {
System.out.println();
HelloInter inter = (x, y) -> x + y;
System.out.println(inter.calcData(4, 5));
}
}
위의 경우에서는 HelloInter inter = (x, y) -> x + y; 쪽에서 아래와 같은 오류 메시지가 출력된다.
The target type of this expression must be a functional interface
추상 메서드가 1개인 경우 메서드의 이름을 사용하지 않고 찾아갈 수 있다.
💻 @FunctionalInterface
여러 개의 디폴트 메서드가 있더라도 추상 메서드가 오직 하나인 함수형 인터페이스를 말한다.
@FunctionalInterface
interface HelloInter {
int calcData(int a, int b);
int calcData2(int a, int b);
}
이런 경우, 아래와 같은 오류메시지가 나온다.
Invalid '@FunctionalInterface' annotation; HelloInter is not a functional interface
람다식은 추상메서드가 1개인 경우에 사용할 수 있다.
위의 어노테이션도 마찬가지로 추상 메서드가 오직 한 개인 함수형 인터페이스에 사용할 수 있다.
때문에 @FunctionalInterface는 람다표현식을 사용할 때 많이 사용되는 어노테이션이다.
👻 정리
람다식은 객체인가? 메서드인가?
람다는 함수형 인터페이스를 구현하는 인터페이스이다.
함수형 인터페이스가 가지고 있는 1개의 추상메서드와 람다가 1:1 매칭을 하게된다.
✔ 함수형 인터페이스 (인자가 없는 추상메서드 처리)
⌨ 코드 (전통적인 방법 + 람다식 표현)
@FunctionalInterface
interface MyInter { // 함수형 인터페이스
void aaa();
}
public class MyLambda2 {
public static void main(String[] args) {
// 1. 인자가 없는 추상메서드 처리 : 전통적인 방법
MyInter inter = new MyInter() {
@Override
public void aaa() {
System.out.println("익명 클래스의 aaa 메소드 오버라이딩");
}
};
inter.aaa();
// 람다식으로 표현 1
MyInter inter2 = () -> System.out.println("일명 클래스 aaa 메서드 오버라이딩 : 람다");
inter2.aaa();
// 람다식으로 표현 2
MyInter inter3 = () -> {
int imsi = 10;
System.out.println("람다식으로");
System.out.println("복수의 명령문 처리");
System.out.println("imsi : " + imsi);
};
inter3.aaa();
}
}
✔ 인자가 있는 추상메서드 처리
💻 코드로 보기
@FunctionalInterface
interface MyInterArg {
void bbb(int a, int b);
}
public class MyLambda2 {
public static void main(String[] args) {
MyInterArg interArg = new MyInterArg() {
@Override
public void bbb(int a, int b) {
System.out.println("두 수의 합은" + (a + b));
}
};
interArg.bbb(3, 4);
// 람다식으로 표현2 : arg가 1개일 경우 (a) -> 또는 a ->로 표현 가능
MyInterArg interArg2 = (a, b) -> System.out.println("람다로 두 수의 합은" + (a + b));
interArg2.bbb(3, 4);
}
}
✔ 반환값이 있고 인자가 있는 추상메서드 처리
💻 코드로 보기
@FunctionalInterface
interface MyInterArgReturn {
int ccc(int a, int b);
}
public class MyLambda2 {
public static void main(String[] args) {
MyInterArgReturn argReturn = new MyInterArgReturn() {
@Override
public int ccc(int a, int b) {
System.out.println("ccc 처리");
return a + b;
}
};
int result = argReturn.ccc(5, 6);
System.out.println("두 수를 더한 결과 : " + result);
// 람다식으로 표현 3
MyInterArgReturn argReturn2 = (m, n) -> (m + n);
MyInterArgReturn argReturn3 = (m, n) -> {
System.out.println("람다 수행 ");
return m + n;
};
int result2 = argReturn3.ccc(5, 6);
System.out.println("두 수를 더한 결과2 : " + result2);
}
}
✔ 표준 함수형 인터페이스
람다식을 사용하기 위해서 늘 함수형 인터페이스를 정의해야하는가?
아니다. 많은 사람들이 이미 만들어 놓은 함수형 인터페이스가 있다.
📑 Runnable
매개변수가 없고 반환값이 없는 경우 사용할 수 있다.
📑Supplier<T>
매개 변수가 없고 반환값이 있는 경우 사용할 수 있다.
📑Consumer<T>
매개변수가 있고 반환값이 없는 경우 사용한다.
📑Function<T,R>
매개변수가 있고 반환값이 있는 경우 사용한다.
📑Predicate<T>
매개변수가 있고 반환값이 boolean형인 경우 사용한다.
표준 함수형 인터페이스 사용 장점
디폴트 메서드를 제공한다.
앞서 정리했듯 함수형 인터페이스는 1개의 추상메서드가 존재한다. 다른 디폴트 메서드, 필드가 있을 수 있다.
사용하는 인터페이스에 따라 디폴트 메서드를 호출하여 새로운 객체를 생성할 수 있다.
🎈 정리
무명(익명) 클래스는 일회용 클래스이다.
즉, 람다로 표현하는 것도 일회용 클래스이다.
무명클래스를 짧게 표현하는 방식이다.