람다
람다식
파라미터를 받아 짧은 코드 블록을 수행하고 필요에 따라 값을 return하는 표현방법
(int I, int j, ...) -> (int x = a + b; ...)
-
파라미터 데이터 타입 생략가능
-
파라미터가 하나인 경우 괄호 생략 가능
-
결과를 반환하는 단일문은 괄호와 return 생략가능
(int a, int b, ...) -> return a + b; //return 생략가능 () -> Math.random(); //
람다식의 특징
- 람다식 내에서 사용되는 지역변수는 final이 붙지 않아도 상수로 간주된다
- 람다식으로 선언된 변수명은 다른 변수명과 중복될 수 없다.
람다식의 장단점
장점
- 코드를 간결하게 만들 수 있다.
- 식에 개발자의 의도가 명확히 드러나 가독성이 높아진다
- 함수를 만드는 과정없이 한번에 처리할 수 있어 생산성이 높아진다
- 병렬프로그래밍이 용이하다
단점
- 람다를 사용하면서 만든 무명 함수는 재사용이 불가능하다
- 디버깅이 어렵다
- 람다를 남발하면 비슷한 함수가 중복 생성되어 코드가 지저분해질 수 있다
- 재귀로 만들 경우에 부적합하다
함수형 인터페이스
람다는 함수형 인터페이스에 접근하여 사용된다.
함수형 인터페이스란 함수를 1급 객체 처럼 다룰 수 있게 해주는 어노테이션, 인터페이스에 선언하여 단 하나의 추상 메소드 만을 갖도록
제한하는 역활을 한다. 여기서 말하는 1급 개체란 아래 3가지 조건을 충족하는 객체를 말할 수 있다.
- 변수나 데이터에 할당 할 수 있어야 한다
- 객체의 인자 넘길 수 있어야 한다
- 객체의 리턴값으로 리턴 할 수 있어야 한다
기본 함수형 인터페이스
| 함수형 인터페이스 | 메서드 | 매개변수 | 반환값 |
|---|---|---|---|
| java.lang.Runnable | void run() | X | X |
| **Supplier |
T get() | X | O |
| **Consumer |
void accept(T t) | O | X |
| Function<T, R> | R apply(T t) | O | O |
| **Predicate |
boolean test(T t) | O | O |
여기서 주의 깊게 봐야 하는 인터페이스는 Cousmer, Function, Predicate로 볼 수 있다.
-
Consumer
Consumer는 객체 T를 매개변수로 받아서 사용하며, 반환값은 없는 함수형 인터페이스이다.
사용자 정렬 구현하는 부분에서 메소드 오버라이딩을 람다식 으로 간단 진행할 수 있다.
// 정의 @FunctionalInterface public interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } } // 예시 Consumer<String> consumer = (str) -> System.out.println(str.split(" ")[0]); consumer.andThen(System.out::println).accept("Hello World"); // 출력 Hello Hello World -
Function
매개변수도 있고, 반환 값도 존재하는 일반적인 적용 함수
import java.util.function.*; public class ETC { public static void main(String[] args) { // Function Function<Integer, Integer> function = (num) -> num + 1; int result1 = function.apply(1); System.out.println(result1); // 2 Function<String, Integer> function2 = String::length; << 메소드 참조 int len = function2.apply("Hello World"); System.out.println(len); } } -
Predicate
매개변수도 있고, 반환값 도 존재하지만, Function과 달리 Boolean 값을 반환한다.
import java.util.function.*;
public class ETC {
public static void main(String[] args) {
// Predicate
Predicate<Integer> predicate = (num) -> num > 0;
boolean result2 = predicate.test(1);
System.out.println(result2); // true
}
}
메소드 참조
메소드 참조란 함수형 인터페이스를 람다식이 아닌 일반 메소드를 참조시켜 선언하는 방법이다.
일반메소드의 참조 조건은 아래 3가지 와 같다
- 함수형 인터페이스의 매개변수 타입 = 메소드의 매개변수 타입
- 함수형 인터페이스의 매개변수 개수 = 메소드의 매개변수 개수
- 함수형 인터페이스의 반환형 = 메소드의 반환형
| 종류 | 람다 | 메서드참조 |
|---|---|---|
| static메서드 참조 | (x) -> ClassName,method(x) | ClassName::method |
| 인스턴스메서드 참조 | (obj, x) -> obj,method(x) | ClassName::method |
| 특종 객체 인스턴스메서드 참조 | (x) -> obj,method(x) | obj::method |
즉 하나의 메서드만 호출하는 람다식은 ‘클래스이름:: 메서드 이름’ , ‘참조변수::메서드이름’ 으로 바꿀 수 있다.
DoubleUnaryOperator oper;
oper = (n) -> Math.abs(n); // 람다 표현식
System.out.println(oper.applyAsDouble(-5));
oper = Math::abs; // 메소드 참조
System.out.println(oper.applyAsDouble(-5));
참고 자료