람다식(Lambda Expression)
메서드를 하나의 식으로 표현한것.
* 메서드를 람다식으로 표현하면 메서드의 이름과 반환값이 없어지므로, 람다식을 익명함수(annonymous function)라고도 한다.
import java.io.IOException;
import java.util.Arrays;
public class Main {
public static void main(String[] args) throws IOException {
int[] arr = new int[5];
for(int e : arr){
System.out.print(e);
}
System.out.println();
// 람다식을 사용하여 배열의 각 요소에 값을 삽입
Arrays.setAll(arr, (i) -> (int)(Math.random()*5) +1);
for(int e : arr){
System.out.print(e);
}
}
}
실행 결과
모든 메서드는 클래스에 포함되어야 하므로 클래스도 새로 만들고 객체도 생성해야만 해당 메서드를 호출할수 있지만, 람다식은 이런 과정없이 자체로 해당 메서드의 역할을 대신한다.
* 메서드: 클래스에 반드시 속해야 하는 제약이 있다
람다식 작성 방법
// 원래의 메서드
int max(int a, int b){
return a > b ? a : b;
}
// 람다식으로 변환
(int a, int b) -> {
a > b ? a : b
}
반환 값이 있는 메서드의 경우, return문 대신 식으로 대신 할수 있다. 식의 연산 결과가 자동적으로 반환값이 되는데, 이때 끝에 ';'을 붙이지 않는다.
(a, b) -> { a > b ? a : b }
또한, 람다식에 선언된 매개변수의 타입은 추론이 가능한 경우 생략할 수 있다. (대부분 생략 가능)
람다식에 반환 타입이 없는 이유도 항상 추론이 가능하기 때문이다
// 수정전
(a) -> a *a
(int b) -> b * b
// 수정후
a -> a * a // ok
int b -> b * b // error
선언된 매개변수가 하나인 경우에 괄호를 생략할수 있다. 하지만 매개변수의 타입이 있으면 생략할수 없다.
// 원래의 메서드
(int a, int b) -> {
return a > b ? a : b;
}
// error
(int a, int b) ->
return a > b ? a : b
또한 괄호{}안에 return문이 있는 경우에도 생략할 수 없다.
함수형 인터페이스(Functional Interface)
람다식을 다루기 위한 인터페이스로 단 하나의 추상 메서드만 선언된 인터페이스.
자바에서 모든 메서드는 클래스 내에 포함되어어야 하며, 람다식은 익명 클래스의 객체와 동등하다.
람다식으로 정의된 익명 객체의 메서드를 호출하려면 참조변수가 있어야 한다.
참조 변수로 클래스나 인터페이스를 사용할 수 있고, 참조 변수에는 람다식과 동등한 메서드가 정의되어 있어야 한다. 인터페이스를 사용하여 람다식의 선언부가 일치하도록 익명 객체를 람다식으로 구현하여 사용할 수 있으며, 하나의 메서드가 선언된 인터페이스를 정의해서 람다식을 다루면 자바의 규칙을 어기지 않고 자연스럽다.
* 함수형 인터페이스에는 오직 하나의 추상 메서드만 정의되어야 한다는 제약이 있다.
* 반면에 static메서드와 default메서드의 개수에는 제약이 없다.
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
// 함수형 인터페이스 타입의 참조변수로 람다식 참조
MyFunction f = (a,b) -> a > b ? a : b;
int value = f.max(3,5); // 실제로 람다식이 호출됨
System.out.println(value); // 5
}
}
// 함수형 인터페이스 선언
@FunctionalInterface
interface MyFunction {
int max(int a, int b);
}
익명 객체를 람다식으로 대체하기
interface Comparator<T> {
int compareTo(T o1, T o2);
}
List<String> list = Arrays.asList("abc", "aaa", "bbb", "ddd", "aaa");
// 기존 인터페이스의 메서드 구현
Collections.sort(list, new Comparator<String>() {
public int compare(String s1, String s2) {
return s2.compareTo(s1);
}
}
// 람다식으로 변환
Collections.sort(list, (s1, s2) -> s2.compareTo(s2));
메서드 참조
람다식이 하나의 메서드만 호출하는 경우에는 메서드 참조(method reference)라는 방법으로 람다식을 간략히 할수 있다.
문자열을 정수로 변환하는 람다식을 메서드 참조로 면환하는 예제
* 메서드 참조에서 람다식의 일부가 생략되었지만 컴파일러는 생략된 부분을 쉽게 알아낼수 있다.
MyClass obj = new MyClass();
Function<String, Boolean> f = (x) -> obj.equals(x); // 람다식
Function<String, Boolean> f2 = obj::equals; // 메서드 참조
하나의 메서드만 호출하는 람다식은 클래스이름::메서드이름 또는 참조변수::메서드이름 으로 바꿀수 있다.
생성자의 메서드 참조
생성자를 호출하는 람다식도 메서드 참조로 변환할 수 있다.
Supplier<MyClass> s = () -> new MyClass(); // 람다식
Supplier<MyClass> s = MyClass::new; // 메서드 참조
매개변수가 있는 생성자의 경우,
Supplier<Integer, MyClass> s = (i) -> new MyClass(i); // 람다식
Supplier<Integer, MyClass> s = MyClass::new; // 메서드 참조
Supplier<Integer, String, MyClass> str = (i,s) -> new MyClass(i,s); // 람다식
Supplier<Integer, MyClass> str = MyClass::new; // 메서드 참조
배열을 생성할 경우,
Function<Integer, int[]> f = x -> new int[x]; // 람다식
Function<Integer, int[]> f = int[]::new; // 메서드 참조
'Language > Java' 카테고리의 다른 글
15. 스트림(stream) (0) | 2021.08.04 |
---|---|
14. java.util.function 패키지 (0) | 2021.08.04 |
12.4 쓰레드(Thread) - Lock과 Condition을 이용한 동기화 (0) | 2021.07.29 |
12.3 쓰레드(Thread) - Synchronized를 이용한 동기화 (0) | 2021.07.29 |
12.2 쓰레드(Thread) - 실행 제어 (0) | 2021.07.28 |