개발지/Today I learn

[0824-25] 자바 람다식(람다식, 함수형 인터페이스)

개발지의 개발자 2023. 8. 25. 18:01

#람다식

- 함수형 프로그래밍 기법을 지원하는 자바의 문법요소.

- 메서드를 하나의 '식'으로 표현한 것.

- 코드를 간결하고 명확하게 표현할 수 있다.

- 객체지향 프로그래밍과 함수형 프로그래밍을 혼합하는 방식으로 더 효율적 프로그래밍 가능.

- 람다식과 기존 메서드의 비교

// 기존 메서드
void sayhi() {
    System.out.println("HI");
}

// 람다식 
() -> System.out.println("HI");

- 람다식은 반환타입과 이름을 생략할 수 있어, 익명 함수(anonymous function)이라고도 부른다.

- 람다식 예시 코드

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

(int num1, int num2) -> { // 반환타입과 메서드명 삭제 + 화살표 추가
    return num1 + num2;
}
 
// 기존 방식
void example3(String str) {
    System.out.println(str);
}

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

- 특정 조건 총족시 람다식의 더욱 축약할 수 있다.

// 기존 방식
int sum(int num1, int num2) {
    return num1 + num2;
}

// 람다식
(int num1, int num2) -> { 
    num1 + num2
}

// 메서드 바디에 실행문이 하나만 존재할 때, 중괄호와 return문을 생략 가능
(int num1, int num2) -> num1 + num2 // 세미콜론도 생략된다.

// 매개변수 타입을 함수형 인터페이스를 통해 유추할 수 있는 경우 매개변수 타입을 생략 가능
(num1, num2) -> num1 + num2

 

 

# 함수형 인터페이스

- 기존의 인터페이스 문법을 활용하여 람다식을 다루는 것

- 람다식 또한 객체이기 때문에 클래스를 통해 만들어야 한다.

- 람다식은 이름이 없는 익명객체이기 때문에 익명 클래스를 통해 만들어진다.

- 익명 클래스는 객체의 선언과 생성을 동시에 하여 오직 하나의 객체를 생성하고, 단 한 번만 사용되는 일회용 클래스이다.

- 이 때 익명 클래스의 특징으로 인해, 선언한 람다식 메서드를 외부에서 사용하지 못하는 문제가 생긴다.

  이를 해결하기 위해 자바의 함수형 인터페이스 문법을 활용하여 람다식을 다룬다.

- 함수형 인터페이스의 특징은 단 하나의 추상 메서드만 선언될 수 있다.

- 익명 클래스로 쓰여진 람다식과 함수형 인터페이스로 쓰여진 람다식의 비교

public class LamdaExample1 { // 익명클래스 활용
    public static void main(String[] args) {
    
        Object obj = (num1, num2) -> num1 + num2;
        
        obj.sum(5, 7);
    }
}

/* 출력결과
  error: cannot find symbol
        obj.sum(5, 7);
           ^
  symbol:   method sum(int,int)
  location: variable obj of type Object
*/

public class LamdaExample2 { // 함수형 인터페이스 활용
    public static void main(String[] args) {
        ExampleFunction exampleFunction = (num1, num2) -> num1 + num2;
        System.out.println(exampleFunction.sum(5,15));
}

@FunctionalInterface // 컴파일러가 인터페이스가 바르게 정의되었는지 확인하는 어노테이션
interface ExampleFunction {
		int sum(int num1, int num2);
}

// 출력값
20

 

#매개변수와 리턴값이 없는 람다식의 함수형 인터페이스 활용

- 매개변수를 가지지 않는 메서드를 가진 함수형 인터페이스를 람다식으로 작성할 때 다음과 같이 작성할 수 있다.

@FunctionalInterface
interface MyfunctionalInterface {
    void accept();
}

public class MyFunctionalInterfaceExample {
    public static void main(String[] args) throws Exception {
        MyFuntionalInterface example = () -> System.out.println("accept()가 호출됩니다");
        example.accept();
    }
}

// 출력값
accept()가 호출됩니다

 

#매개변수가 있는 람다식의 함수형 인터페이스 활용

- 매개 변수는 있고 리턴값이 없는 메서드를 가진 함수형 인터페이스를 람다식을 작성할 때 다음과 같이 작성할 수 있다.

public class MyFunctionalInterfaceExample {

    public static void main(String[] args) throws Exception {
    
        MyFunctionalInterface example;
        example = (x) -> {
            int result = x * 10;
            System.out.println(result);
        };
        exampel.accept(5);
        
        example = (x) -> System.out.println(x * 10);
        example.accept(5);
    }
}

// 출력값
50
50

 

#리턴값이 있는 람다식의 함수형 인터페이스 활용

- 매개 변수와 리턴값을 가지는 추상 메서드를 포함하는 함수형 인터페이스를 람다식으로 작성할 때 다음과 같이 작성할 수 있다.

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(10, 5);
        System.out.println(result1);
        
        example = (x, y) -> { return x - y; };
        int result2 = example.accept(10, 5);
        System.out.println(result2);
       
        example = (x, y) ->  x - y;
        //return문만 있으면, 중괄호 {}와 return문 생략 가능
        int result3 = example.accept(10, 5);
        System.out.println(result3);
       
        example = (x, y) -> sum(x, y);
        //return문만 있으면, 중괄호 {}와 return문 생략 가능
        int result4 = example.accept(5, 5);
        System.out.println(result4);
    }

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

//출력값
5
5
5
10