자바 람다식(Lambda Expression)과 메서드 참조(Method Reference)

coldrice99·2024년 9월 9일
0

1. 람다식 (Lambda Expression)

람다식이란?

람다식은 자바 8에서 도입된 익명 함수로, 메서드를 간결하게 표현하는 방식이다. 메서드 이름과 반환형, 접근 제어자 등을 쓰지 않고도, 함수를 간단하게 작성할 수 있어 코드 가독성이 높아진다.

2. 람다식의 구조

람다식은 기본적으로 다음과 같은 형태를 가진다:

(매개변수) -> { 실행할 코드 }

이것을 더 구체적으로 설명해 보면:

  • 매개변수: 메서드처럼 입력 값을 받는 부분이다.
  • ->: 화살표 연산자는 람다식에서 매개변수와 실행할 코드를 구분한다.
  • { 실행할 코드 }: 매개변수를 가지고 처리할 실제 코드이다.

예시:

기본적인 람다식 예시로, 두 숫자를 더하는 메서드를 람다식으로 표현할 수 있다.

(int a, int b) -> { return a + b; }

3. 람다식의 기본 예시

기존 방식과 비교해 보자.

기존 방식:

public interface Adder {
    int add(int a, int b);
}

Adder adder = new Adder() {
    @Override
    public int add(int a, int b) {
        return a + b;
    }
};
System.out.println(adder.add(5, 3)); // 출력: 8

이 코드는 인터페이스를 구현한 익명 클래스를 생성해서 두 수를 더하는 코드다. 이 코드를 람다식으로 바꾸면 다음과 같다.

람다식 사용:

Adder adder = (a, b) -> a + b;
System.out.println(adder.add(5, 3)); // 출력: 8

4. 매개변수와 코드 블록 생략

람다식은 다음과 같은 규칙을 가지고 있어 더 간결하게 작성할 수 있다:

  1. 매개변수가 하나일 때는 괄호 생략 가능

    • 매개변수가 하나라면 괄호를 생략할 수 있다.
    Consumer<String> printer = s -> System.out.println(s);
  2. 코드가 한 줄일 때는 중괄호와 return 생략 가능

    • 코드 블록이 한 줄일 경우 중괄호와 return을 생략할 수 있다.
    (a, b) -> a + b

5. 람다식 사용의 전제 조건: 함수형 인터페이스

람다식을 사용하려면 함수형 인터페이스가 필요하다. 함수형 인터페이스는 단 하나의 추상 메서드만 가지고 있는 인터페이스다. 자바에서 제공하는 몇 가지 함수형 인터페이스를 알아보자:

  • Runnable: 인자가 없고 반환값도 없는 함수형 인터페이스
  • Comparator<T>: 두 개의 값을 비교하는 함수형 인터페이스
  • Predicate<T>: 조건을 테스트해 true 또는 false를 반환하는 함수형 인터페이스

6. 람다식의 예시

1) Runnable 인터페이스 사용 예시:
기본적으로 자바에서 Runnable은 인자가 없고, 반환값도 없는 함수형 인터페이스이다. 람다식을 사용하면 더욱 간결해진다.

Runnable task = () -> System.out.println("Hello, Lambda!");
task.run();

2) Comparator 인터페이스 사용 예시:
Comparator는 두 객체를 비교하는 함수형 인터페이스다. 람다식을 사용하여 숫자를 비교하는 방법은 다음과 같다.

Comparator<Integer> comparator = (a, b) -> a - b;
int result = comparator.compare(3, 2);
System.out.println(result); // 출력: 1 (3이 2보다 큼)

3) Predicate 인터페이스 사용 예시:
Predicate는 특정 조건을 검사하고, true 또는 false를 반환하는 함수형 인터페이스다.

Predicate<String> isEmpty = s -> s.isEmpty();
System.out.println(isEmpty.test("")); // 출력: true

2. 메서드 참조 (Method Reference)

람다식과 함께 자바 8에서 도입된 또 다른 중요한 기능은 메서드 참조이다. 메서드 참조는 람다식에서 사용되는 메서드 호출을 간결하게 표현하기 위해 사용된다. 메서드 참조는 :: 기호를 사용하여 작성된다.

메서드 참조의 형태

메서드 참조는 아래와 같은 방식으로 표현된다:

  • 정적 메서드 참조: 클래스명::메서드명
  • 인스턴스 메서드 참조: 인스턴스명::메서드명
  • 생성자 참조: 클래스명::new

메서드 참조의 예시

1) 정적 메서드 참조

정적 메서드를 참조하는 방식이다. 예를 들어 String.valueOf() 메서드를 메서드 참조로 표현하면 아래와 같다.

Function<Integer, String> func = String::valueOf;
System.out.println(func.apply(123)); // 출력: "123"

2) 인스턴스 메서드 참조

인스턴스의 메서드를 참조하는 방식이다. 다음은 System.out.println() 메서드를 메서드 참조로 표현한 예시다.

Consumer<String> printer = System.out::println;
printer.accept("Hello, Method Reference!"); // 출력: Hello, Method Reference!

3) 생성자 참조

객체의 생성자를 참조하는 방식이다. 아래는 ArrayList의 생성자를 메서드 참조로 표현한 예시다.

Supplier<List<String>> listSupplier = ArrayList::new;
List<String> list = listSupplier.get();

메서드 참조와 람다식 비교

람다식과 메서드 참조는 매우 비슷하지만, 메서드 참조는 더 간결하게 표현할 수 있다. 아래는 람다식과 메서드 참조를 비교한 예시이다.

람다식 사용:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 람다식으로 대문자로 변환
names.stream()
     .map(name -> name.toUpperCase())
     .forEach(name -> System.out::println);

메서드 참조 사용:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 메서드 참조로 대문자로 변환
names.stream()
     .map(String::toUpperCase)
     .forEach(System.out::println);

메서드 참조는 단순히 메서드를 호출하는 람다식의 경우 더 간결하게 사용할 수 있다.


2. 메서드 참조 (Method Reference)

메서드 참조람다식을 간결하게 표현하는 방법이다. 람다식에서 특정 메서드를 호출하는 경우, 메서드 참조를 통해 해당 메서드를 바로 참조할 수 있다. 메서드 참조는 자바 8에서 도입되었으며, :: 연산자를 사용한다.

메서드 참조의 종류

메서드 참조는 다음과 같이 4가지 형태로 나뉜다:

  1. 정적 메서드 참조: 클래스의 정적 메서드를 참조할 때 사용한다.

    • 형식: 클래스명::메서드명
    • 예: String::valueOf
  2. 인스턴스 메서드 참조: 특정 객체의 인스턴스 메서드를 참조할 때 사용한다.

    • 형식: 인스턴스명::메서드명
    • 예: System.out::println
  3. 임의 객체의 인스턴스 메서드 참조: 특정 클래스의 임의의 객체의 인스턴스 메서드를 참조할 때 사용한다.

    • 형식: 클래스명::메서드명
    • 예: String::toUpperCase
  4. 생성자 참조: 객체 생성자를 참조할 때 사용한다.

    • 형식: 클래스명::new
    • 예: ArrayList::new

3. 람다식과 메서드 참조 비교

람다식과 메서드 참조는 서로 대체할 수 있는 개념이다. 메서드 참조는 더 간결하게 메서드를 호출할 수 있게 해준다.

예시 1: 정적 메서드 참조

람다식 사용:

Function<Integer, String> func = (i) -> String.valueOf(i);

메서드 참조 사용:

Function<Integer, String> func = String::valueOf;

두 코드는 동일하게 작동하지만, 메서드 참조는 더 간결한 표현이다.

예시 2: 인스턴스 메서드 참조

람다식 사용:

Consumer<String> printer = (str) -> System.out.println(str);

메서드 참조 사용:

Consumer<String> printer = System.out::println;

이 코드 역시 메서드 참조가 훨씬 간단하게 표현된다.

4. 메서드 참조의 예시

예시 1: 리스트의 숫자를 문자열로 변환하기

람다식 사용:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> strings = numbers.stream()
                              .map(n -> String.valueOf(n))
                              .collect(Collectors.toList());
System.out.println(strings); // 출력: [1, 2, 3, 4, 5]

메서드 참조 사용:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<String> strings = numbers.stream()
                              .map(String::valueOf)
                              .collect(Collectors.toList());
System.out.println(strings); // 출력: [1, 2, 3, 4, 5]

예시 2: 리스트의 문자열을 대문자로 변환하기

람다식 사용:

List<String> names = Arrays.asList("alice", "bob", "charlie");
List<String> upperNames = names.stream()
                               .map(name -> name.toUpperCase())
                               .collect(Collectors.toList());
System.out.println(upperNames); // 출력: [ALICE, BOB, CHARLIE]

메서드 참조 사용:

List<String> names = Arrays.asList("alice", "bob", "charlie");
List<String> upperNames = names.stream()
                               .map(String::toUpperCase)
                               .collect(Collectors.toList());
System.out.println(upperNames); // 출력: [ALICE, BOB, CHARLIE]

5. 요약

  • 람다식은 메서드를 간결하게 표현하는 방식이다. 함수형 인터페이스와 함께 사용된다.
  • 메서드 참조는 이미 존재하는 메서드를 간단히 참조하여 더 간결하게 람다식을 표현할 수 있는 방법이다. :: 연산자를 사용하여 클래스나 인스턴스의 메서드를 참조한다.

람다식과 메서드 참조는 자바 8에서 도입된 중요한 기능으로, 코드 가독성과 간결함을 높일 수 있다.


profile
서두르지 않으나 쉬지 않고

0개의 댓글