우당탕탕 개발일지

[Java] java8 람다식(Lambda expression)이란? 본문

Java

[Java] java8 람다식(Lambda expression)이란?

kyunge_ev 2022. 11. 30. 22:27

※ '자바의정석'을 기반으로 공부한 내용을 작성합니다.

🌈 https://cafe.naver.com/javachobostudy

✏ 람다식(Lambda expression)이란?

  • 익명함수(anonymous function)라고도 불림 👉 메서드를 람다식으로 표현하면 '반환값'과 '메서드이름'이 없어짐
  • 메서드를 하나의 '(expression)'으로 표현한 것 👉 함수를 간략하면서도 명확한 식으로 표현할 수 있음
1
2
3
4
5
6
7
8
9
int[] arr = new int[5];
 
// 람다형식 익명함수
Arrays.setAll(arr, (i) -> (int)(Math.random() * 5+ 1);
 
// 원래 메서드로 표현할 때
int method() {
    return (int)(Math.random() * 5+ 1;
}
cs
Arrays 란? 
(블로그 작성예정)
Arrays 클래스에는 배열을 다루는데 유용한 메서드들이 정의되어 있음정의된 메서드 모두 static 메서드임같은 기능의 메서드가 배열의 타입만 다르게 오버로딩 되었을 뿐 그리 많지는 않음
Arrays.setAll() : 배열을 채우는데 사용할 함수형 인터페이스를 매개변수를 받는다.👉 함수형객체나 람다식을 매개변수로 지정해야함

📌람다식 장점

  1. 메서드보다 간결하면서도 이해하기 쉽다.
  2. 메서드처럼 클래스나 객체 생성없이도 람다식 하나로 메서드의 역할을 대신할 수 있다.
  3. 메서드의 매개변수로 전달되어 질 수 있고, 메서드의 결과로 반환 될 수도 있다.
    👉 람다식으로 인해 메서드를 '변수'처럼 다루는 것이 가능해졌음

📌람다식 작성

    • 메서드에서 이름, 반환타입을 제거하고 매개변수 선언부와 몸통'{}' 사이에 '->'를 추가한다.
1
2
3
4
5
6
7
int max(int a, int b) {
    return a > b ? a : b;
}
 
(int a, int b) -> {
    return a > b ? a : b;
}
cs
  • 반환값이 있는 메서드인 경우 return문 대신 '식(expression)'으로 대신 할 수 있다.
    👉 return문이 없어도 식의 연산결과가 자동적으로 반환
  • 문장이 아닌 '식'이므로 끝에 ';'를 붙이지 않는다.
(int a, int b) -> {
    return a > b ? a : b;
}

(int a, int b) -> {
    a > b ? a : b
}
  • 람다식에 선언된 매개변수의 타입이 추론이 가능하다면 생략할 수 있다.
    • 둘 중 하나의 타입만 생략하는것은 불가능 👉 아래와 같이 둘다 생략해야함
(int a, int b) -> a > b ? a : b

(a,b) -> a > b ? a : b
  • 매개변수가 하나인 경우 괄호( ) 를 생략 할 수 있다. 
    • 단, 매개변수 타입이 있는 경우 생략 불가
(a)     -> a * a
(int a) -> a * a

a -> a * a
int a -> a * a // 에러)
  • 중괄호 { } 안의 문장이 하나일 때는 생략할 수 있다.
  • 문장 끝에 ';' 붙이지 않는다.
(String name, int i) -> {
    System.out.println(name+"="+i);
}

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

📌함수형 인터페이스(Functional Interface)

  • 아래의 코드와 같이 람다식은 익명 객체!
// 람다식
(a,b) -> a > b ? a : b

// 익명 클래스 객체
new Object() {
    int max(int a, int b) {
        return a > b ? a : b;
    }
}
  • 익명 객체이기 때문에 참조변수에 저장해서 사용할 수 있다.
    • 객체 = 클래스 👉 클래스 객체를 사용하기 위해선 `Object obj = new Object();` 이렇게 사용하는 것처럼!
  • 참조변수명은 원하는대로 정의 가능하지만 타입은 클래스 또는 인터페이스만 정의할 수 있음
    • 람다식의 참조변수 타입은 그럼 어떤걸로 해야할까?
  • 답은 ? 함수형 인터페이스를 사용
    • 람다식을 사용하기 위한 인터페이스 
      👉 함수형 인터페이스와 람다식의 매개변수 / 반환타입이 일치해야 사용가능
    • 단 하나의 추상 메서드만 선언된 인터페이스
    • 람다식과 인터페이스의 메서드가 1:1로 연결되어야함
    • @Functionallnterface 를 붙이면 컴파일러가 함수형 인터페이스를 올바르게 정의했는지 확인해줌
      (없어도 에러는 아님)
@FunctionalInterface
interface MyFunction {
    public abstract int max(int a, int b);
}
    // 익명 클래스
    MyFunction f = new MyFunction() {
        public int max(int a, int b) {
            return a > b ? a : b;
        }
    };

    // 람다식
    MyFunction f = a,b -> a > b ? a : b

    int big = f.max(6,3);
더보기
더보기

[ 익명클래스 구현]

 

타입 참조변수명 = new  조상이름() { [사용할메서드] }

 

- 조상이름에는 클래스 or 인터페이스가 옴

- 클래스의 선언, 객체 생성을 동시에 하는 것

📌함수형 인터페이스의 매개변수, 반환타입

  • 함수형 인터페이스를 매개변수로 넘길 수 있다. (= 람다식을 매개변수로 받는다는 것)
@FunctionalInterface
interface MyFunction {
    void run();
}
public class Example {
    // 매개변수의 타입이 MyFunction(함수형인터페이스)인 메서드
    // 람다식을 넘겨받는다는 뜻
    static void execute(MyFunction f) {
        f.run();
    }

    public static void main(String[] args) {
        MyFunction f1 = () -> System.out.println("f1.run()");

//        execute(() -> System.out.println("f1.run()"));
        execute(f1);
        // 결과 -> f1.run()
        execute(() -> System.out.println("run()"));
        // 결과 -> run()
    }

}
  • 함수형 인터페이스 타입으로 반환할 수 있다. (= 람다식으로 반환한다는 것)
@FunctionalInterface
interface MyFunction {
    void run();
}
public class Example {
    static MyFunction getMyFunction() {
        return () -> System.out.println("f2.run()");
    }

    public static void main(String[] args) {
        MyFunction f2 = () -> System.out.println("f2.run()");
        f2.run();
        // 결과 -> f2.run()
    }

}