Formoat's Open Blog
람다 표현식(Lambda Expression) 본문
2019/09/03 - [Java] - 함수적 인터페이스 - Consumer
2019/09/03 - [Java] - 함수적 인터페이스 - Supplier
2019/09/03 - [Java] - 함수적 인터페이스 - Function
2019/09/03 - [Java] - 함수적 인터페이스 - Operator
2019/09/03 - [Java] - 함수적 인터페이스 - Predicate
1. 람다식이란?
1) y =f(x) 형태의 함수형 프로그래밍 기법
2) 데이터를 매개 값으로 전달해 결과를 받는 코드로 구성
3) 람다 함수를 사용하여 불필요한 루프 문을 삭제해 코드가 간결해짐
4) 대용량 데이터 처리, 데이터 병렬 처리, 이벤트 지향 프로그래밍에 적합
5) 함수적 인터페이스는 모두 람다식에 사용 가능하다
2. 기본 문법
// 익명 구현 객체
Interface inter = new Interface() {
@Override
public void method() { ... }
};
--------------------------------------------------------------
// 람다식 기본문법
Interface inter = () -> { ... };
위처럼 함수적 인터페이스를 익명 구현객체로서 표현하는 방법에서 람다식으로 표현하는 방법으로 간결하게 코드를 작성할 수 있다.
3. 약식 표현
// 매개변수 타입 생략 가능
Interface inter = (int x) -> { System.out.println(x); };
Interface inter = (x) -> { System.out.println(x); };
// 매개변수가 하나일 경우 괄호() 생략 가능
Interface inter = (x) -> { System.out.println(x); };
Interface inter = x -> { System.out.println(x); };
// 매개변수가 없으면 괄호() 생략 불가
Interface inter = () -> { ... };
// 실행문이 하나일 경우 중괄호{} 생략 가능
Interface inter = x -> { System.out.println(x); };
Interface inter = x -> System.out.println(x);
// 반환값이 있는 경우 return문 사용
Interface inter = (x, y) -> {
int a = x + 10;
int b = y + 20;
return a - b; };
// 중괄호{}에 return문만 있는 경우 중괄호{}와 return문 생략 가능
Interface inter = (x, y) -> { return x + y; };
Interface inter = (x, y) -> return x + y;
4. 표준API 함수적 인터페이스
1) 자바 1.8부터 표준 API로 제공
2) java.util.function 패키지에 포함
3) 반환값과 매개 값에 따라 아래와 같은 함수적 인터페이스들이 있다.
5. 디폴트 메소드
1) andThen(), compose() 디폴트 메소드
(1) 자바 표준 API 함수적 인터페이스들이 공통적으로 가지고 있는 디폴트 메소드
(2) 두 개의 함수적 인터페이스를 순차적으로 연결해서 실행
(3) 여러개의 함수적 인터페이스를 이용해 최종 결과값을 받아야 할 때 사용
(4) andThen()과 compose()의 차이점은 어떤 함수적 인터페이스부터 처리하느냐의 차이
Kind | Functional Interface | andThen() | compose() |
Consumer | Consumer<T> | ○ | |
BiConsumer<T, U> | ○ | ||
DoubleConsumer | ○ | ||
IntConsumer | ○ | ||
LongConsumer | ○ | ||
Function | Function<T, R> | ○ | ○ |
BiFunction<T, U, R> | ○ | ||
Operator | BinaryOperator<T> | ○ | |
DoubleUnaryOperator | ○ | ○ | |
IntUnaryOperator | ○ | ○ | |
LongUnaryOperator | ○ | ○ |
<표> andThen(), compose() 디폴트 메소드를 제공하는 함수적 인터페이스들
# andThen() : A를 먼저 실행한 후 A의 결과값을 B의 매개값으로 이용하고 B의 결과값이 최종 결과값이 된다.
Interface AB = Interface A.andThen(Interface B);
결과값 = Interface AB.method();
# compose() : B를 먼저 실행한 후 B의 결과값을 A의 매개값으로 이용하고 A의 결과값이 최종 결과값이 된다.
Interface AB = Interface A.compose(Interface B);
결과값 = Interface AB.method();
LambdaExample1.java
public class LambdaExample1 {
public static void main(String[] args) {
Consumer<String> csmA = s -> System.out.println("csmA의 Consumer "+s);
Consumer<String> csmB = s -> System.out.println("csmB의 Consumer "+s);
Consumer<String> csmAB = csmA.andThen(csmB);
csmAB.accept("hello");
IntUnaryOperator optA = x -> x + 100;
IntUnaryOperator optB = x -> x - 50;
IntUnaryOperator optAB = optA.andThen(optB);
int result = optAB.applyAsInt(100);
System.out.println(result);
IntUnaryOperator optBA = optA.compose(optB);
int result2 = optBA.applyAsInt(100);
System.out.println(result2);
}
}
// 실행결과 //
----------------------------------------------------
csmA의 Consumer hello
csmB의 Consumer hello
150
150
2) and(), or(), negate() 디폴트 메소드
(1) Predicate 함수적 인터페이스들이 공통적으로 가지고 있는 디폴트 메소드
(2) 두개의 Predicate를 이용해 and, or, not 연산을 할 때 사용 된다.
Kind | Functional Interface | and() | or() | nagate() |
Predicate | Predicate<T> | ○ | ○ | ○ |
BiPredicate<T, U> | ○ | ○ | ○ | |
DoublePredicate | ○ | ○ | ○ | |
IntPredicate | ○ | ○ | ○ | |
LongPredicate | ○ | ○ | ○ |
<표> and(), or(), negate() 디폴트 메소드를 제공하는 함수적 인터페이스들
# and() : &&과 같은 의미로 두개의 Predicate가 모두 true일 경우 true를 반환
ex) Predicate AB = Predicate A.and(Predicate B);
# or() : ||와 같은 의미로 두개의 Predicate 중 하나라도 true일 경우 true를 반환
ex) Predicate AB = Predicate A.or(Predicate B);
# negate() : !과 같은 의미로 Predicate의 결과의 반대값을 반환
ex) Predicate AB = Predicate A.negate();
LambdaExample2.java
public class LambdaExample2 {
public static void main(String[] args) {
// 2의 배수인지 검사
IntPredicate pdcA = a -> a % 2 == 0;
// 3의 배수인지 검사
IntPredicate pdcB = a -> a % 3 == 0;
//pdcA와 pdcB를 and연산
IntPredicate pdcAB = pdcA.and(pdcB);
boolean result = pdcAB.test(6);
System.out.println("6은 2와 3의 배수인가? " + result);
//pdcA와 pdcB를 or연산
IntPredicate pdcAB2 = pdcA.or(pdcB);
boolean result2 = pdcAB2.test(5);
System.out.println("5는 2또는 3의 배수인가? " + result2);
//pdcA의 not연산
IntPredicate pdcAN = pdcA.negate();
boolean result3 = pdcAN.test(20);
System.out.println("20은 홀수인가? "+result3);
}
}
// 실행결과 //
----------------------------------------------------
6은 2와 3의 배수인가? true
5는 2또는 3의 배수인가? false
20은 홀수인가? false
6. 메소드 참조 (Method references)
1) 메소드를 참조해 매개 변수의 정보, 반환 타입을 알아내 람다식을 좀더 간결하게 작성
2) 람다식에서 매개값과 반환 타입이 동일한 하나의 메소드만 호출할 때 사용가능
3) 정적 메소드의 경우 클래스와 메소드를 대입
4) 인스턴스 메소드의 경우 인스턴스를 생성하여 인스턴스 참조변수와 메소드를 대입
// 람다식
str -> System.out.println(str);
(left, right) -> Math.max(left, right);
// 메소드 참조
System.out::println;
Math::max;
# 정적 메소드 참조 -> 클래스 :: 메소드;
# 인스턴스 메소드 참조 -> 참조변수 :: 메소드;
MethodReferencesExample1.java
public class MethodReferencesExample1 {
public static int staticMethod(int x, int y) {
return x + y;
}
public int instanceMethod(int x, int y) {
return x + y;
}
public static void main(String[] args) {
//정적 메소드
IntBinaryOperator operator;
operator = (x, y) -> MethodReferencesExample1.staticMethod(x, y);
System.out.println("정적 메소드 람다식: "+operator.applyAsInt(1, 2));
operator = MethodReferencesExample1::staticMethod;
System.out.println("정적 메소드 참조: "+operator.applyAsInt(3, 4));
//인스턴스 메소드
MethodReferencesExample1 example = new MethodReferencesExample1();
operator = (x, y) -> example.instanceMethod(x, y);
System.out.println("인스턴스 메소드 람다식: "+operator.applyAsInt(5, 6));
operator = example::instanceMethod;
System.out.println("인스턴스 메소드 참조: "+operator.applyAsInt(7, 8));
}
}
// 실행결과 //
----------------------------------------------------
정적 메소드 람다식: 3
정적 메소드 참조: 7
인스턴스 메소드 람다식: 11
인스턴스 메소드 참조: 15
# 매개변수의 메소드 참조 -> 클래스 :: 메소드;
MethodReferencesExample2.java
public class MethodReferencesExample2 {
public static void main(String[] args) {
ToIntBiFunction<String, String> function;
function = (a, b) -> a.compareTo(b);
System.out.println(function.applyAsInt("Hello", "hello"));
// 아래의 String은 String 타입의 변수인 a와 같다.
function = String::compareTo;
System.out.println(function.applyAsInt("Hello", "hello"));
}
}
// 실행결과 //
----------------------------------------------------
-32
-32
# 생성자 참조 -> 클래스 :: new
MethodReferencesExample3.java
public class MethodReferencesExample3 {
public static void main(String[] args) {
BiFunction<String, String, Member> function;
function = (a, b) -> new Member(a, b);
Member m1 = function.apply("hong", "홍길동");
function = Member::new;
Member m2 = function.apply("kim", "김태호");
System.out.println(m1.toString());
System.out.println(m2.toString());
}
}
// 실행결과 //
----------------------------------------------------
Member [userId=hong, userName=홍길동]
Member [userId=kim, userName=김태호]
'Java > Java Basic' 카테고리의 다른 글
함수적 인터페이스 - Operator (0) | 2019.09.03 |
---|---|
함수적 인터페이스 - Function (0) | 2019.09.03 |
함수적 인터페이스 - Supplier (0) | 2019.09.03 |
함수적 인터페이스 - Consumer (0) | 2019.09.03 |
자바 (0) | 2019.09.03 |