개발/java

Java의 람다 표현식 과 스트림

바이솔 2024. 7. 12. 17:30

람다 표현식이란?

람다 표현식은 익명 함수(anonymous function)를 작성하는 간결한 방법이다. 람다 표현식을 사용하면 코드가 더욱 간결해진다.

람다 표현식의 기본 문법

(매개변수 목록) -> { 함수 본문 }

람다 표현식의 사용법

 

예제 1) Runnable 인터페이스 구현

Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello, world!");
    }
};

 

Runnable r = () -> System.out.println("Hello, world!");

 

예제 2: Comparator 인터페이스 구현

Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer a, Integer b) {
        return a.compareTo(b);
    }
};

 

Comparator<Integer> comparator = (a, b) -> a.compareTo(b);

 

 

스트림(Stream)이란?

 

스트림 은 다양한 데이터 소스(컬렉션, 배열 등)를 표준화하여 다루는 방법입니다. 통합된 방식으로 데이터를 핸들링할 수 있으며, 스트림을 사용하여 선언적(무엇을 할 것인지 설명)으로 데이터 처리를 표현할 수 있습니다.

 

스트림 API의 주요 특징

  • 다양한 데이터 소스: 컬렉션, 배열, I/O 채널 등 다양한 데이터 소스를 스트림으로 다룰 수 있다.
  • 통합된 방식: 일관된 API를 통해 데이터 소스를 처리할 수 있다.
  • 스트림 생성 - 중간 연산 - 최종 연산: 스트림 API는 스트림 생성, 중간 연산, 최종 연산의 세 단계로 구성된다.
  • 지연 처리: 중간 연산은 지연 처리(lazy evaluation)되어 최종 연산이 실행될 때까지 실제로 수행되지 않는다.
  • 병렬 처리: 스트림 API는 병렬 처리를 지원하여 멀티코어 프로세서를 효율적으로 활용할 수 있다.

 

스트림의 기본 구조

스트림은 데이터를 순차적으로 처리할 수 있는 연속적인 요소이다. 스트림은 다음 세 단계로 구성된다:

  1. 스트림 생성
  2. 중간 연산
  3. 최종 연산

1) 스트림 생성

스트림은 컬렉션, 배열 등에서 생성할 수 있다.

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();

2) 중간 연산

중간 연산은 스트림을 변환하거나 필터링하는 연산이다. 중간 연산은 지연 처리되며, 최종 연산이 호출될 때까지 실제로 수행되지 않는다. 중간 연산은 스트림을 반환하여 연속적인 처리가 가능하다.

  • filter: 조건에 맞는 요소만 포함하는 스트림을 반환한다.
  • map: 각 요소를 변환하여 새로운 요소로 매핑하는 스트림을 반환한다.
  • sorted: 스트림의 요소를 정렬한다.

3) 최종 연산

최종 연산은 스트림을 소비하여 결과를 반환하거나 출력한다. 최종 연산 후 스트림은 더 이상 사용할 수 없다.

  • forEach: 각 요소를 처리한다.
  • collect: 스트림의 요소를 컬렉션으로 모은다.
  • reduce: 스트림의 요소를 하나의 값으로 결합한다.

스트림 예시 1

import java.util.Arrays;
import java.util.List;

public class StreamExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);

        list.stream()  // 스트림 생성
            .filter(n -> n % 2 == 0)  // 짝수만 필터링 (중간 연산)
            .map(n -> n * n)  // 각 숫자를 제곱 (중간 연산)
            .forEach(System.out::println);  // 각 요소를 출력 (최종 연산)
    }
}

스트림 예시 2

import java.util.Arrays;
import java.util.List;

public class StreamExample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("apple", "banana", "apple", "orange", "banana", "kiwi");

        list.stream()  // 스트림 생성
            .distinct()  // 중복 제거 (중간 연산)
            .sorted()  // 정렬 (중간 연산)
            .forEach(System.out::println);  // 각 요소를 출력 (최종 연산)
    }
}

스트림 API와 람다 표현식의 결합

스트림 API에서 중간 연산과 최종 연산에 람다 표현식을 활용하여 데이터를 처리할 수 있다. 

 

다음은 스트림 API와 람다 표현식을 사용하여 리스트에서 짝수만 필터링하고 각 숫자를 제곱한 값을 출력하는 예제이다.

import java.util.Arrays;
import java.util.List;

public class StreamExample {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);

        list.stream()  // 스트림 생성
            .filter(n -> n % 2 == 0)  // 짝수만 필터링 (중간 연산)
            .map(n -> n * n)  // 각 숫자를 제곱 (중간 연산)
            .forEach(System.out::println);  // 각 요소를 출력 (최종 연산)
    }
}

 

  • stream(): 리스트를 스트림으로 변환한다.
  • filter(n -> n % 2 == 0): 람다 표현식을 사용하여 짝수만 필터링하는 중간 연산을 수행한다.
  • map(n -> n * n): 람다 표현식을 사용하여 각 숫자를 제곱하는 중간 연산을 수행한다.
  • forEach(System.out::println): 메서드 참조를 사용하여 각 요소를 출력하는 최종 연산을 수행한다.