본문 바로가기

프로그래밍언어/Java

람다식

0. 개요

- 자바는 OOP 언어이다.

- 빅데이터 처리의 요구가 늘어나며 함수형 언어의 기능에대한 필요성이 증대했다.

 

1. 람다식이란

- 함수(메서드)를 간단한 식으로 표현하는 익명함수

- 익명함수란 이름이 없는 함수이다. 

- 함수와 메서드는 근본적으로 동일하나 함수는 일바적 용어인 반면 메서드는 객체지향 개념의 용어이다.

- 함수는 클래스에 독립적이나, 메서드는 클래스에 종속적이다. 자바의 모든 함수는 클래스 내에서 선언되므로 모든 함수는 메서드라 지칭한다.

// 메서드
int max(int a, int b) {
    return a > b ? a : b;
}

// 람다식
(a, b) -> a > b ? a : b;

 

 

2. 람다식의 특징

- 메서드의 이름과 반환타입을 제거하고 화살표(->)를 블록 앞에 추가한다.

- 반환값이 있을 경우 return이나 세미콜론(;)를 생략한 채로 식이나 값만을 적는다. 

- 매개변수의 타입이 추론 가능할 경우 생략 가능하다. (대부분의 경우 생략 가능하다.)

- 매개변수가 하나이고 타입이 없는 경우 괄호 ()가 생략 가능하다. 

a -> a * a  // OK
int a -> a * a  // 에러
(int a) -> a * a  // OK

- 블록 안의 문장이 하나인 경우 괄호를 생략할 수 있다. 또한 이 때, 식의 끝에 세미콜론을 붙이지 않는다.

(int i) -> {
    System.out.println(i);
}

(int i) -> System.out.println(i)  // 문장이 하나인 경우 {} 생략, ; 생략

- 하나뿐인 문장이 return문인 경우 괄호 {} 생략 불가 

(int a, int b) -> ( return a > b ? a : b; )  // OK
(int a, int b) -> return a > b ? a : b  // error

- 람다식의 예

(a, b) -> a > b ? a : b

(name, i) -> System.out.println(name + "=" + i)

x -> x * x

() -> (int) Math.random() * 6

- 자바에서 람다식은 익명 함수가 아닌 익명 객체이다. 자바의 함수는 모두 클래스에 종속된 메서드이기 때문에 람다식 역시도 익명 함수가 아닌 익명 객체이다. 즉, 익명함수는 객체이기 때문에 참조변수가 필요하다. 

// 자바의 람다식은 익명 클래스와 동등하다. 
(a, b) -> a > b ? a : b

// 익명 클래스 : 객체의 선언과 생성을 동시에 한다. 
new Object() {
    int max(int a, int b) {
        return a > b ? a : b;
    }
}

- 자바 람다식의 참조변수타입은 Object가 될 수 있으나 호출이 불가능하다. 

Object obj = (a, b) -> a > b ? a : b // 에러 -> 람다식은 익명객체이다.

// 익명객체를 생성하고 호출해 보았다.
Object obj = new Object() {
    int max(int a, int b) {
        return a > b ? a : b;
    }
};
int value = obj.max(3, 5);  // 에러 -> 함수형 인터페이스가 필요하다.

 

 

3. 함수형 인터페이스

- 함수형 인터페이스란? : 단 하나의 추상 메서드만 선언된 인터페이스 

- 기본적으로 추상 메서드는 인터페이스에 선언된 메서드이다. 만약 이 추상 메서드가 오직 한개라면 함수형 인터페이스라고 한다. 

@FunctionalInterface  // 어노테이션을 작성한 경우 컴파일러가 올바르게 작성되었는지 확인한다. 
interface MyFunction {
    public abstract int max(int a, int b);  // public abstract는 생략이 가능하다. 인터페이스의 추상 메서드는 반드시 public이다.
}

// 익명 클래스를 통해 함수형 인터페이스의 max 메서드를 구현한다. 
// 이 때, 클래스의 선언과 객체의 생성이 동시에 이루어진다. 
Myfunction f = new MyFunction() {
                   @Override  // 오버라이딩의 규칙에 따라 접근제어자는 좁게 못바꾼다. 반드시 public이다.
                   public int max(int a, int b) {
                       return a > b ? a : b;
                   }
               };
               
int value = f.max(3, 5);  // OK. MyFunction에 max()가 있으며 호출할 수 있다.

- 익명 객체에서와 마찬가지로 람다식을 함수형 인터페이스 타입으로 참조할 수 있다. 단, 함수형 인터페이스의 메서드와 람다식의 매개변수 개수, 반환타입이 일치해야 한다.

MyFunction f = (a, b) -> a > b ? a : b;
int value = f.max(3, 5);  // 람다식이 호출됨

- 즉 람다식(익명 객체)을 호출하기 위해 필요한 참조 변수의 타입은 함수형 인터페이스이다. 

 

 

- 람다식은 익명객체를 대신한다. 아래는 메서드의 매개 변수로 함수형 인터페이스인 Comparator를 요구하고 있다. 함수형 인터페이스는 익명객체나 람다식을 참조한다. 

List<String> list = Arrays.asList("abc", "aaa", "bbb", "Ddd", "aaa");

Collections.sort(list, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s2.compareTo(s1);
    }
});

Collections.sort(list, (s1, s2) -> s2.compareTo(s1));

 

- 함수형 인터페이스 타입을 매개 변수로 가질 수 있다.

- 함수형 인터페이스 타입을 반환할 수 있다. (람다식을 반환한다.)

import java.io.*;

class Main {
    public static void main(String[] args) throws IOException {
        MyFunction f1 = () -> System.out.println("f1.run");
        MyFunction f2 = new MyFunction() {
            @Override
            public void run() {
                System.out.println("f2.run");
            }
        };
        MyFunction f3 = getMyFunction();

        f1.run();
        f2.run();
        f3.run();
        execute(f1);
        execute(() -> System.out.println("run"));
    }

    static MyFunction getMyFunction() {
        return () -> System.out.println("f3.run");
    }
    static void execute(MyFunction f){
        f.run();
    }
}

@FunctionalInterface
interface MyFunction {
    void run();
}

 

 

 

 

'프로그래밍언어 > Java' 카테고리의 다른 글

Java Lambda Expression, 자바8 람다식  (0) 2023.06.21
Java Collection Framework (JCF)  (0) 2023.06.21
가변객체와 불변객체  (0) 2023.05.23
자바 어노테이션  (0) 2023.05.21
[Java] Optional이 모길래???  (0) 2023.04.13