자바가 처음 등장한 이후로 두 번의 큰 변화가 있었는데, 한번은 JDK1.5부터 추가된 제네릭스(Generics)
의 등장이고, 또 한 번은 JDK1.8부터 추가된 람다식(Lambda expression)
이다.
이 람다식의 등장으로 인해 자바는 객체지향언어인 동시에 함수형 언어가 되었다.
이 람다식에 대해 자세히 알아보자.
람다식은 간단히 말해서
메서드를 하나의 식(Expression)으로 표현한 것
람다식은 함수를 간략하면서도 명확한 식으로 표현할 수 있게 해준다.
간단한 예제를 살펴보면, 다음과 같은 메서드를
int method(){
return (int)(Math.random()*5) + 1;
}
아래의 Arrays.setAll
의 두 번째 인자와 같이 바꿀 수 있다.
int[] arr = new int[5];
Arrays.setAll(arr, (i) -> (int)(Math.random()*5) + 1);
모든 메서드는 클래스에 포함되어야 하므로 클래스도 새로 만들어야 하고, 객체도 생성해야만 위의 메서드를 호출할 수 있다. 하지만, 람다식은 이 모든 과정없이 오직 람다식 자체만으로도 이 메서드의 역할을 대신할 수 있다.
게다가, 람다식은
✔ 메서드의 매개변수로 전달되어지는 것이 가능
✔ 메서드의 결과로 반환될 수 있다
람다식은
메서드에서 이름과 반환타입을 제거하고 매개변수 선언부와 몸통{} 사이에 '->'를 추가한다.
반환타입 메서드이름(매개변수 선언){
문장들
}
⬇
(매개변수 선언) -> {
문장들
}
예를 들어, 두 값 중 큰 값을 반환하는 메서드 max를 람다식으로 변환하면 다음과 같다.
int max(int a, int b){
return a > b ? a : b;
}
⬇
(int a, int b) -> {
return a > b ? a : b;
}
반환값이 있는 메서드의 경우,
return
문 대신식(expression)
으로 대신 할 수 있다. 식의 연산결과가 자동적으로 반환되는 것이다.
이때는문장
이 아닌식
이므로 끝에;
을 붙이지 않는다.(int a, int b) -> {return a>b ? a:b;} ➡ (int a, int b) -> a>b ? a:b
람다식에 선언된 매개변수의 타입은 추론이 가능한 경우 생략할 수 있다(대부분의 경우 생략 가능)
(int a, int b) -> a>b ? a:b ➡ (a, b) -> a>b ? a:b
두 매개변수 중 하나의 타입만 생략하는 것은 불가능
아래와 같이 선언된 매개변수가 하나뿐인 경우에는 괄호( )를 생략할 수 있다.
(a) -> a * a
(int a) -> a * a
⬇
a -> a * a
int a -> a * a
마찬가지로 괄호 { } 안의 문장이 하나일 때는 생략할 수 있는데, 이 때 문장의 끝에 ;
을 붙이지 않아야 한다는 것에 주의하자!
(String name, int i) -> {
System.out.println(name + "=" + i);
}
⬇
(String name, int i) -> System.out.println(name + "=" + i)
하지만, 괄호 { } 안의 문장이
return
문일 경우 괄호{ }를 생략할 수 없다.
자바에서 모든 메서드는 클래스 내에 포함되어야 하는데, 람다식은 어떤 클래스에 포함되는 것일까? 위에서 람다식이 메서드와 동등한 것처럼 설명했지만, 사실 람다식은 익명 클래스의 객체와 동등하다.
(int a, int b) -> a>b ? a:b
⬇
new Object() {
int max(int a, int b){
return a>b ? a:b;
}
}