Java - Lambda

진경천·2024년 9월 24일

Java

목록 보기
5/9

메서드를 하나의 식으로 표현
함수형 프로그래밍 지원
자바에서는 람다식을 익명 구현 객체로 변환

람다 표현식의 기본 구조

(parameter1, parameter2) -> {
	statement1;
	statement2;
	statement3;
	...
}

람다식을 활용하면 변수에 함수를 할당할 수 있다.

MyFunction f = (x, y) -> x + y;
f.sum();

장점

  • 간결성: 코드를 간결하게 만들어 코드 가독성 향
  • 지연 실행: 실행될 필요가 있을 때까지 코드 실행 지연 가
  • 병렬 처리 용이: 병렬 처리를 쉽게 구현할 수 있음
  • 고차 함수 지원: 함수를 매개 변수로 넘기거나 결과 값으로 반환

단점

  • 문서화를 할 수 없다
  • 코드가 복잡해지면 디버깅이 어려울 수 있다.
  • stream에서 람다를 사용할 시 for문보다 성능이 떨어짐
  • 람다를 남발하면 가독성이 떨어짐
  • 재귀로서 부적합

익명 객체와 람다

new MyInterface(){
	@Override
    public void foo(int num){
    	System.out.println(num);
    }
}

MyInterface mi = number -> System.out.println(number);

mi.foo(1)	// 1 출력

위 코드와 같이 람다는 인터페이스를 선언하고 그에 대한 메서드를 정의한다는 점에서 익명객체와 비슷한 구조로 이루어져있다.

익명 객체를 람다식으로 표현하기 위해서는 인터페이스가 단 하나의 추상 메서드만 가져야한다.
그도 그럴 것이 람다는 메서드명, 타입을 모두 생략하고 표현하기 때문에 람다가 구현할 추상메서드는 하나이어야 한다.

이러한 추상메서드를 단 하나마 가지는 인터페이스를 함수형 인터페이스라고 한다.

람다 표현식의 요건

  • 함수형 인터페이스가 필요.
  • 매개변수와 반환 값의 타입 일치 필요.
  • 로컬 변수는 final이어야 함.

함수형 인터페이스

단 하나의 추상 메서드를 지닌 인터페이스

@FunctionalInterfae
public interface MyFunction{
	int sum(int a, int b);
}

@FunctionalInterface 에너테이션은 함수형 인터페이스를 구현할 때 2개 이상의 추상메서드가 선언되지 않도록 컴파일 타임에 체크하기 위함이다.

에너테이션은 선택 사항이나 붙이는걸 권장한다.

함수형 인터페이스는 아래와 같이 표준 API가 정의되어 있다.

인터페이스 메서드 설명 매개변수 리턴
Runnable void run() 매개변수를 사용하지 않고, 리턴을 하지 않는 함수 형태로 이용
Consumer<T> void accept(T t) 매개변수만 사용하고 리턴을 하지 않는 함수 형태로 이용
Supplier<T> T get() 매개변수를 사용하지 않고, 리턴을 하지 않는 함수 형태로 이용
Function<T, R> R apply(T t) 매개변수 값을 매핑(타입 변환)해서 리턴
Predicate<T> boolean test(T t) 매개변수값이 조건에 맞는지 단정해서 boolean 리턴
Operator R applyAs(T t) 매개변수값을 연산해서 결과 리턴

메서드 참조

메서드를 참조해서 매개변수와 리턴타입의 정보를 알아내어 람다식의 불필요한 부분을 생략가능하다.

종류 람다 표현식 메서드 참조
정적 메서드 참조 (x) -> Class.method(x) Class::method
인스턴스 메서드 참조 (x) -> obj.method(x) obj::method
매개변수의 메서드 참조 (obj, x) -> obj.method(x) Class::method
생성자 메서드 참조 (x, y) -> new Class(x, y) Class::new

정리

import java.lang.FunctionalInterface;

// 함수형 인터페이스 정의
@FunctionalInterface
interface MyFunction1 {
    int sum(int a, int b);
}

public class Main {
    public static void main(String[] args) {
        // 익명 객체(익명 클래스)를 사용해 함수형 인터페이스 구현
        MyFunction1 f0 = new MyFunction1() {
            @Override
            public int sum(int a, int b) { return a + b; }
        };
        // 람다 표현식으로 f1 변수에 함수를 저장
        MyFunction1 f1 = (a, b) -> a + b;

        // Integer 클래스 내의 sum 메서드를 참조함
        MyFunction1 f2 = Integer::sum;

        int res0 = f0.sum(1, 2);
        int res1 = f1.sum(3, 4);
        int res2 = f2.sum(5, 6);
        // 메서드의 매개변수의 입력값으로 람다식을 넘김
        int res3 = add((a, b) -> a + b);

        System.out.println("익명객체 : " + res0);	// 3
        System.out.println("람다 : " + res1);		// 7
        System.out.println("메서드 참조 : " + res2);	// 11
        System.out.println("add메서드 : " + res3);	// 3
    }

    public static int add(MyFunction1 lambda){
        return lambda.sum(1, 2);
    }
}
profile
어중이떠중이

0개의 댓글