반응형
JDK1.8(자바8) 부터 추가된 람다식(lambda expression)의 도입으로 인해, 자바는 객체지향언어인 동시에 함수형 언어가 되었다.
람다식이란 ?
- 메서드를 하나의 식(expression)으로 표현한것
- 함수를 간략하면서도 명확한 식으로 표현할 수 있게 해줌
- 메서드를 람다식으로 표현하면 메서드의 이름과 반환값이 없어지므로, 익명 함수(anonymous function)라고도 한다.
람다식을 쓰는 이유
int[] arr = new int[5];
Arrays.setAll(arr, (i) -> (int) (Math.random()*5)+1);
// 위의 람다식 ‘() → (int) (Math.random()*5)+1’ 을 메서드로 표현하면
int method() {
return (int) (Math.random()*5) + 1;
}
- 람다식을 사용하지 않으면 모든 메서드는 클래스에 포함되어야 하므로 클래스도 새로 만들어야하고, 객체도 생성해야만 메서드를 호출할 수 있음
- 람다식은 이 모든 과정없이 람다식 자체만으로도 메서드의 역할을 대신할 수 있다.
- 람다식은 메서드의 매개변수로 전달되어지는 것이 가능하며, 메서드의 결과로 반환될 수도 있다.
람다식으로 인해 메서드를 변수처럼 다루는 것이 가능해진 것
람다식 작성
- 이름과 반환타입을 제거하고 매개변수 선언부와 몸통{} 사이에 - >를 추가한다.
// 변경전
int max(int a, int b) {
return a > b ? a : b;
}
// 변경후
(int a, int b) -> {
return a > b ? a : b;
}
- 반환값이 있는 메서드일 경우, return문 대신 식(expression) 으로 대신 할 수 있음
- 식의 연산결과가 자동적으로 반환값이 됨
- 문장(statement)이 아닌 식이므로 끝에 ; 를 붙이지 않는다.
(int a, int b) { return a > b ? a : b; } —> (int a, int b) → a > b ? a : b
- 매개변수의 타입은 대부분 생략 가능(추론이 가능하기 때문)
(a, b) → a > b ? a : b
- 선언된 매개변수가 하나뿐인 경우에는 괄호() 생략 가능(매개변수의 타입이 있다면 생략 불가)
(a) → a * a ⇒ a → a * a
- 마찬가지로 괄호{} 안의 문장이 하나일 때는 괄호 생략 가능, 생략시 문장의 끝에 ;를 붙이면 안됨
- 괄호{} 안의 문장이 return문일 경우 괄호 생략 불가
함수형 인터페이스(Functional Interface)
- 람다식은 익명 클래스의 객체와 동등
- 람다식으로 정의된 익명 객체의 메서드를 호출하는 방법
타입 f = (int a, int b) → a > b ? a : b;
- 참조변수 f 의 타입은 클래스 또는 인터페이스가 가능하며, 동등한 메서드가 정의되어 있는 것이어야 한다.
- 하나의 메서드가 선언된 인터페이스를 정의해서 람다식을 다루는 것이 자바의 규칙을 어기지 않으며 자연스러움
- 람다식을 다루기 위한 인터페이스를 함수형 인터페이스(functional interface)라고 부르기로함
제약
- 함수형 인터페이스에는 오직 하나의 추상 메서드만 정의되어 있어야함
- 그래야 람다식과 인터페이스의 메서드가 1:1로 연결될 수 있기 때문
- static메서드와 default메서드의 개수에는 제약X
- @FunctionalInerface를 꼭 붙이는게 좋음(컴파일러가 확인해준다)
함수형 인터페이스 타입의 매개변수와 반환타입
- 메서드의 매개변수 타입이 함수형 인터페이스라면 메서드를 호출할 때 람다식을 참조하는 참조변수를 매개변수로 지정해야 한다.
- 참조변수 없이 직접 람다식을 매개변수로 지정하는 것도 가능하다.
- 메서드의 반환타입이 함수형 인터페이스 타입이라면, 함수형 인터페이스의 추상메서드와 동등한 람다식을 가리키는 참조변수를 반환하거나 람다식을 직접 반환 가능
- 람다식을 참조변수로 다룰 수 있다는 것은 메서드를 통해 람다식을 주고받을 수 있다는 것을 의미 ⇒ 변수처럼 메서드를 주고받는 것이 가능해진 것
- 코드가 간결하고 이해하기 쉬워짐
package LambdaStream;
@FunctionalInterface
interface MyFunction {
void run(); // public abstract void run();
}
public class LambdaEx1 {
static void execute(MyFunction f) { // 매개변수의 타입이 MyFunction인 메서드
f.run();
}
static MyFunction getMyFunction() {
MyFunction f = () -> System.out.println("f3.run()");
return f;
}
public static void main(String[] args) {
// 람다식으로 MyFunction의 run()을 구현
MyFunction f1 = () -> System.out.println("f1.run()");
MyFunction f2 = new MyFunction() { // 익명 클래스로 run()을 구현
@Override
public void run() {
System.out.println("f2.run()");
}
};
MyFunction f3 = getMyFunction();
f1.run();
f2.run();
f3.run();
execute(f1);
execute(() -> System.out.println("run()") );
}
}
/*
출력결과
f1.run()
f2.run()
f3.run()
f1.run()
run()
*/
java.util.function패키지
- 일반적으로 자주 쓰이는 형식의 메서드를 함수형 인터페이스로 미리 정의해 놓음.
- 자주 쓰이는 가장 기본적인 함수형 인터페이스
- java.lang.Runnable
- void run()
- 매개변수도 없고, 반환값도 없음
- void run()
- Supplier<T>
- T get()
- 매개변수는 없고, 반환값만 있음
- T get()
- Consumer<T>
- void accept(T t)
- Supplier와 반대로 매개변수만 있고, 반환값이 없음
- void accept(T t)
- Function<T,R>
- R apply(T t)
- 일반적인 함수. 하나의 매개변수를 받아서 결과를 반환
- R apply(T t)
- Predicate<T>
- boolean test(T t)
- 조건식을 표현하는데 사용됨, 매개변수는 하나, 반환타입은 boolean
- boolean test(T t)
- java.lang.Runnable
반응형