[Java] Lambda Expressions
Java 8버전 부터 지원하는 기능으로 코드를 간결하고 효율적으로 작성할 수 있게 도와주는 기능이다.
기존 익명 클래스의 단점으로 메서드가 하나만 포함되는 것처럼 간단한 인터페이스를 익명 클래스의 구문을 이용해 다루기에는 비효율적이고 복잡하다는 것이다.
이런 비효율적인 인스턴스 생성을 간단하게 표현할 수 있는 것이 Lambda이며 익명 함수를 의미한다.
메서드를 작성하기 위해서는 클래스가 있어야하고, 이를 인스턴스화 해야 메소드를 사용할 수 있다.
하지만 람다는 이런 과정을 간소화 시켜주는 역할이기 때문에 람다식 자체가 메서드의 역할을 대신할 수 있다.
함수형 프로그래밍의 개념을 Java에 도입한 케이스라 할 수 있다.
작성 하기
일단 람다의 기본 구조는 아래와 같다.
(매개 변수) -> 실행 코드
매개 변수는 입력으로 받는 값을 맵핑할 수 있고, 이 Input 된 값을 표현식에서 가공하여 사용할 수 있다.
매개 변수는 ,
를 기준으로 여러개를 받아올 수 있다.
만약 매개 변수를 하나도 받지 않는다면
() -> 실행 코드
로 표현하면 된다.
이제 기존의 선언부와 람다를 비교해보자
[기존 선언 방법]
[Return type] [Method name] (Parameters) {
[Statements]
}
[Lambda식 사용]
(Parameters) -> {
[Statements]
}
기존 선언 방법에서 [Return type] [Method name]
가 지워지고 (Parameters)
뒤에 ->
가 붙었다.
익명 함수라고 소개한 것 처럼 일단 이름은 필요 없다.
이를 토대로 최고 값을 return하는 max라는 method를 만들어보자.
int max(int a, int b){
return a > b ? a : b;
}
이를 람다식으로 만들어보자
(int a, int b) -> { return a > b ? a : b;}
끝이다.
간결하지 않은가?
하지만 여기서 몇 가지 규칙을 적용하여 같은 동작이지만 다르게 표현할 수도 있다.
return은 생략 가능하다.
동작 수행 후 return 되는 값을 return
문장 없이 람다식을 작성할 수 있다.
이 때는 { ;}
과 동시에 return
이 움직인다 생각하고 return
과 동시에 { ;}
도 빼고 작성한다.
(int a, int b) -> a > b ? a : b
타입 추론으로 Parameter type은 생략 가능하다.
일단 타입 추론의 개념은 타입을 명시적으로 선언하지 않아도 컴파일러가 리터럴 값이나 식을 기반으로하여 필요한 타입을 자동으로 추론하는 것을 얘기한다.
이 개념을 적용시킨다면
(a, b) -> a > b ? a : b
가 된다.
매개변수가 1개인 경우 괄호는 생략 가능하다.
(int a) -> { return a*a; }
의 코드가 있다하면 위의 return 생략과 타입 추론으로 Parameter tyep을 걷어낼 수 있다.
(a) -> a*a
이렇게 말이다.
여기서 parameter가 하나이고, parameter type을 타입 추론으로 표현한 경우에는 ()
또한 생략 가능하다.
a -> a*a
그럼 이제 실제 코드에서 활용해보자.
활용
Interface와 interface의 method를 익명 클래스와 익명 함수(람다식)을 이용해 구현해보겠다.
paramter가 없는 경우
public class Lambda {
//구현 되지 않은 interface
interface Drawable{
public void draw();
}
public static void main(String[] args) {
int width=10;
// Lambda 식 없이 사용할 경우 익명 클래스로 Drawable을 구현해준다.
Drawable d=new Drawable(){
public void draw(){System.out.println("Drawing "+width);}
};
d.draw();
//람다식을 사용할 경우
//Drawable의 draw는 parameter를 받지 않으니 () -> { } 의 타입으로 구현한다.
Drawable d2=()->{
System.out.println("Drawing "+width);
};
d2.draw();
}
}
[output]
Drawing 10
Drawing 10
Parameter가 여러개
public class Lambda {
interface Addable{
int add(int a,int b);
}
public static void main(String[] args) {
// 여러개의 parameter가 있을 때 (타입 추론)
Addable ad1=(a,b)->(a+b);
System.out.println(ad1.add(10,20));
// 여러개의 parameter가 있을 때 (타입 선언)
Addable ad2=(int a,int b)->(a+b);
System.out.println(ad2.add(100,200));
}
}
[output]
30
300
와 같이 작성할 수 있고 여기선 타입 추론과 return 생략의 개념도 사용되었다.
Multiple Statements
return 문이 여러줄일 때 사용하는 방법이다.
public class Lambda {
@FunctionalInterface
interface Sayable{
String say(String message);
}
public static void main(String[] args) {
Sayable person = (message)-> {
String str1 = "I would like to say, ";
String str2 = str1 + message;
return str2;
};
System.out.println(person.say("time is precious."));
}
}
여기서 @FunctionalInterface
이 사용되었는데 이또한 Java 8에서 도입되었다.
함수형 인터페이스라는 것을 표시하기 위해 사용되며, 함수형 인터페이스는 추상 메서드가 하나만 정의 된 인터페이스를 의미한다.
사용함으로써 추상 메서드가 하나만 정의 되었는지 컴파일러가 규칙에 잘 지켜졌는지 검증해주는 역할을 부여한다.
Creating Thread
람다식으로 보통 Thread와 함께 활용되는 Runnable 인터페이스를 구현하는 코드를 많이 활용된다.
public static void main(String[] args) {
//익명 함수로 구현.
Runnable r1=new Runnable(){
public void run(){
System.out.println("Thread1 is running...");
}
};
Thread t1=new Thread(r1);
t1.start();
//람다식으로 구현
Runnable r2=()->{
System.out.println("Thread2 is running...");
};
Thread t2=new Thread(r2);
t2.start();
}
[output]
Thread1 is running...
Thread2 is running...
Foreach Loop
Collection Framework의 순회와 필터링을 효율적이고 간결하게 표현하는데 사용 가능하다.
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("ankit");
list.add("mayank");
list.add("irfan");
list.add("jai");
list.forEach(
(n) -> System.out.println(n)
);
}
[output]
ankit
mayank
irfan
jai
위와 같이 수행되는 이유는…
ArrayList는 Collection을, Collection은 Iterable을 extends한다.
forEach는 Iterable 인터페이스에 정의된 메서드이며 Parameter로 Consumer<? super T> action
를 받아오는데 Consumer는 단일 매개 변수를 받아서 return하지 않아도 되는 객체를 받아서 구현한다.
ArrayList 선언 시 String 을 제공하였고, list.add로 Collection에 담긴 단일 객체가 Cosumer로 구현되고 (n) 을 통해서 하나하나 for문을 돌며 출력이 된다…
Collection Framework는 이외에도 Comparator, Filter 등에 활용하는 방법이 있긴하지만 여기선 따로 언급하지 않겠다.