본문 바로가기

코딩공부

Java Lambda의 개념

람다(Lambda)

람다식(Lambda Expression)은 함수형 프로그래밍 기법을 지원하는 자바의 문법요소입니다.

람다식은 수학자 알론조 처치(Alonzo Church)가 발표한 람다 계산법에서 시작되었는데, 이를 그의 제자 존 맥카시(John McCarthy)가 프로그래밍 언어에 도입하면서 본격적으로 컴퓨터 프로그래밍 언어에서 사용되기 시작했습니다.

람다식은 간단히 말해서 메서드를 하나의 ‘식(expression)’으로 표현한 것으로, 코드를 매우 간결하면서 명확하게 표현할 수 있다는 큰 장점이 있습니다.

 

최근 함수형 프로그래밍이 다시금 주목을 받게 되면서 자바도 JDK 1.8 이후 람다식 등 함수형 프로그래밍 문법 요소를 도입하면서 기존의 객체지향 프로그래밍과 함수형 프로그래밍을 혼합하는 방식으로 더욱 효율적인 프로그래밍을 할 수 있게 되었습니다.

람다식은 객체지향적 언어의 특성을 가진 자바의 특성에 따라 일반적인 함수가 아니라 익명의 객체이기 때문에 기존 자바의 문법 요소를 해치지 않으면서 함수형 프로그래밍 기법을 사용할 수 있는 장치가 필요했습니다. 이에 따라 함수형 인터페이스(functional interface가 만들어지게 되었습니다.

 

람다식의 기본 문법

//기존 메서드 표현 방식
void sayhello() {
System.out.println("HELLO!")
}

//위의 코드를 람다식으로 표현한 식
() -> System.out.println("HELLO!")

 

 

람다식에서는 기본적으로 반환타입과 이름을 생략할 수 있다는 점입니다. 따라서 람다함수를 종종 이름이 없는 함수, 즉 익명 함수(anonymous function)라 부르기도 합니다.

 

아래 예시를 통해 메서드를 람다식으로 만드는 방법에 대해 살펴보도록 하겠습니다.

int sum(int num1, int num2) {
return num1 + num2;
}

 

위 예시에 람다식을 적용하여 바꾸게 되면 아래와 같이 나타낼 수 있게 됩니다.

(int num1, int num2) -> { // 반환타입과 메서드명 제거 + 화살표 추가
return num1 + num2;
}



(int num1, int num2) -> num1 + num2;

 

앞서 봤던 것처럼, 반환타입과 메서드명을 제거하고 코드 블록 사이에 화살표를 추가해 주면 됩니다.

 

다음의 예시들도 함께 살펴봅시다.

// 기존 방식
void example1() {
System.out.println(5);
}

// 람다식
() -> {System.out.println(5);}





// 기존 방식
int example2() {
return 10;
}

// 람다식
() -> {return 10;}





// 기존 방식
void example3(String str) {
System.out.println(str);
}

// 람다식
(String str) -> { System.out.println(str);}

 

메서드 바디에 문장이 실행문이 하나만 존재할 때 우리는 중괄호와 return 문을 생략할 수 있습니다. 이 경우, 세미콜론까지 생략해야 합니다.

 

 

 

함수형 인터페이스

자바에서 함수는 반드시 클래스 안에서 정의되어야 하므로 메서드가 독립적으로 있을 수 없고 반드시 클래스 객체를 먼저 생성한 후 생성한 객체로 메서드를 호출해야 합니다.

이런 맥락에서 지금까지 우리가 메서드와 동일시 여겼던 람다식 또한 사실은 객체입니다. 더 정확히는 이름이 없기 때문에 익명 객체라 할 수 있습니다.

 

// sum 메서드 람다식
(num1, num2) -> num1 + num2

// 람다식을 객체로 표현
new Object() {     //오브젝트 생성자. 인스턴스화
int sum(int num1, int num2) {      // 매서드 선언
return num1 + num2;
}
}

 

위는 람다식을 이용하여 표현한 익명객체 입니다.

익명 객체는 익명 클래스를 통해 만들 수 있는데, 익명 클래스객체의 선언과 생성을 동시에 하여 오직 하나의 객체를 생성하고, 단 한 번만 사용되는 일회용 클래스입니다.

 

public class LamdaExample1 {
    public static void main(String[] args) {

        // 람다식 Object obj = (num1, num2) -> num1 + num2; 로 대체 가능
        Object obj = new Object() {
            int sum(int num1, int num2) {
                return num1 + num1;
            }
        };

        obj.sum(1, 2);
    }
}

출력 결과
java: cannot find symbol
  symbol:   method sum(int,int)
  location: variable obj of type java.lang.Object

 

 

함수형 인터페이스에는 단 하나의 추상 메서드만 선언될 수 있는데, 이는 람다식과 인터페이스의 메서드가 1:1로 매칭되어야 하기 때문입니다.

 

public class LamdaExample1 {
    public static void main(String[] args) {
        /* Object obj = new Object() {
            int sum(int num1, int num2) {
                return num1 + num2;
            }
        };
        */
        ExampleFunction exampleFunction = (num1, num2) -> num1 + num2;
        System.out.println(exampleFunction.sum(10,15));
}

@FunctionalInterface // 컴파일러가 인터페이스가 바르게 정의되었는지 확인하도록 합니다.
interface ExampleFunction {
int sum(int num1, int num2);
}

// 출력값
25

 

위와 같이 람다식을 활용하기 위해서는 함수형 인터페이스가 필수이며, 람다식에 사용해야하므로 함수형 인터페이스는 단 하나의 추상메서드만 할당이 가능한 것입니다.

 

 

@FunctionalInterface
interface MyFunctionalInterface {
    void accept();
}


public class MyFuntionalInterfaceExample {
    public static void main(String[] args) throws Exception {
        MyFunctionalInterface example = () -> System.out.println("accept() 호출");
        example.accept();
        example =
                () -> System.out.println("메서드 바디 변경");
        example.accept();
    }
}

 

출력값

accept() 호출
메서드 바디 변경

 

 

[예시]

@FunctionalInterface
interface MyFunctionalInterface {
    int accept(int x, int y);
}


public class MyFunctionalInterfaceExample {

    public static void main(String[] args) throws Exception {

        MyFunctionalInterface example;

        example = (x, y) -> {
            int result = x + y;
            return result;
        };
        int result1 = example.accept(2, 5);
        System.out.println(result1);


        example = (x, y) -> { return x + y; };
        int result2 = example.accept(2, 5);
        System.out.println(result2);


        example = (x, y) ->  x + y;
        //return문만 있으면, 중괄호 {}와 return문 생략 가능
        int result3 = example.accept(2, 5);
        System.out.println(result3);


        example = (x, y) -> sum(x, y);
        //return문만 있으면, 중괄호 {}와 return문 생략 가능
        int result4 = example.accept(2, 5);
        System.out.println(result4);

    }

    public static int sum(int x, int y){
        return x + y;
    }
}

 

출력값

7

7

7

7

'코딩공부' 카테고리의 다른 글

Database Management System  (0) 2024.04.26
Java Stream의 개념  (0) 2024.04.22
Java Annotation  (0) 2024.04.22
Java Collection class 종류 정리  (0) 2024.04.19
Java Map  (2) 2024.04.19