[JAVA] Stream API

1. Stream이란?

Stream은 데이터 소스를 추상화하여 요소의 연속적인 흐름(데이터 스트림)을 처리하는 Java API입니다. Stream은 다음과 같은 특징을 가집니다:

  • 데이터를 변경하지 않음: 원본 데이터는 변경되지 않고 새로운 결과를 생성.
  • 재사용 불가: 한 번 처리한 Stream은 다시 사용할 수 없음.
  • 지연 연산: 필요할 때만 연산이 실행.

 


 

Stream 객체 생성 없이 사용 가능

Java 8 이전에는 데이터 처리를 위해 반복문과 명령형 프로그래밍 방식으로 코드를 작성해야 했습니다. 하지만 Java 8 이후로는 Stream API를 통해 데이터를 더 선언적으로 처리할 수 있습니다. 예를 들어:

  • 컬렉션의 stream() 메서드: 리스트, 세트, 맵 등의 컬렉션은 자체적으로 stream() 메서드를 제공하여 Stream 객체를 생성합니다.
  • Stream 객체 생성 없이 직접 메서드 체이닝으로 데이터 처리 가능.
import java.util.List;

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

        // Stream 객체를 생성하지 않고 메서드 체이닝으로 직접 처리
        numbers.stream()
               .filter(n -> n % 2 == 0) // 짝수 필터링
               .map(n -> n * 2)        // 각 숫자를 2배로 변환
               .forEach(System.out::println); // 결과 출력
    }
}

 


 

2. Stream의 주요 연산

Stream 연산은 크게 두 가지로 나뉩니다:

  1. 중간 연산 (Intermediate Operation): 데이터의 흐름을 변환 또는 필터링합니다.
  2. 최종 연산 (Terminal Operation): 데이터를 소비하고 결과를 반환하거나 출력합니다.

 


 

1. 중간 연산

중간 연산은 lazy execution으로 동작하며, 최종 연산이 호출될 때만 실행됩니다. 주요 중간 연산은 다음과 같습니다.

1) filter()

  • 조건에 맞는 요소만 남기는 연산.
  • 매개변수: Predicate<T> (boolean을 반환하는 람다식).
List<String> names = List.of("Alice", "Bob", "Charlie", "David");

// "A"로 시작하는 이름만 필터링
names.stream()
     .filter(name -> name.startsWith("A"))
     .forEach(System.out::println); // Alice

 


 

2) map()

  • 각 요소를 다른 형태로 변환.
  • 매개변수: Function<T, R> (입력을 다른 출력으로 매핑하는 람다식).
List<Integer> numbers = List.of(1, 2, 3);

// 각 숫자를 문자열로 변환
numbers.stream()
       .map(n -> "Number: " + n)
       .forEach(System.out::println);
// 출력: Number: 1, Number: 2, Number: 3

 


 

3) sorted()

  • 요소를 정렬.
  • 매개변수: Comparator<T> (비교 함수, 생략 시 기본 정렬 기준).
List<String> fruits = List.of("Banana", "Apple", "Orange");

fruits.stream()
      .sorted() // 알파벳 순서로 정렬
      .forEach(System.out::println);
// 출력: Apple, Banana, Orange

 


 

4) distinct()

  • 중복 제거.
  • 매개변수: 없음 (Stream에서 고유한 요소만 선택).
List<Integer> numbers = List.of(1, 2, 2, 3, 3, 4);

numbers.stream()
       .distinct()
       .forEach(System.out::println);
// 출력: 1, 2, 3, 4

 


 

2. 최종 연산

최종 연산은 Stream의 처리를 끝내고 결과를 반환하거나 출력합니다. 주요 최종 연산은 다음과 같습니다.

1) forEach()

  • 각 요소에 대해 지정된 동작을 수행.
  • 매개변수: Consumer<T> (각 요소를 처리하는 람다식).
List<String> items = List.of("Item1", "Item2", "Item3");

items.stream()
     .forEach(System.out::println);
// 출력: Item1, Item2, Item3

 


 

2) collect()

  • 결과를 컬렉션(List, Set 등)으로 반환.
  • 매개변수: Collector<T, A, R> (수집 전략).
import java.util.List;
import java.util.stream.Collectors;

List<Integer> numbers = List.of(1, 2, 3, 4);

// Stream 결과를 리스트로 변환
List<Integer> doubledNumbers = numbers.stream()
                                      .map(n -> n * 2)
                                      .collect(Collectors.toList());

System.out.println(doubledNumbers); // [2, 4, 6, 8]

 


 

3) reduce()

  • 요소를 누적하여 하나의 결과 반환.
  • 매개변수:
    • 초기값(optional): 누적 계산의 시작 값.
    • BinaryOperator<T>: 두 값을 결합하는 연산.
List<Integer> numbers = List.of(1, 2, 3, 4);

// 합계 계산
int sum = numbers.stream()
                 .reduce(0, Integer::sum);

System.out.println(sum); // 10

 


 

4) count()

  • 요소의 개수를 반환.
  • 매개변수: 없음.
List<String> names = List.of("Alice", "Bob", "Charlie");

long count = names.stream()
                  .filter(name -> name.startsWith("A"))
                  .count();

System.out.println(count); // 1

 


 

5) anyMatch(), allMatch(), noneMatch()

  • 요소가 조건을 만족하는지 검사.
  • 매개변수: Predicate<T>.
List<Integer> numbers = List.of(1, 2, 3, 4, 5);

// 조건 만족 여부 확인
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0); // true
boolean allPositive = numbers.stream().allMatch(n -> n > 0); // true
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0); // true

System.out.println(anyEven);     // true
System.out.println(allPositive); // true
System.out.println(noneNegative); // true

 


 

6) findFirst(), findAny()

 

  • Stream에서 첫 번째 요소 또는 아무 요소를 반환.
  • 매개변수: 없음.
List<String> names = List.of("Alice", "Bob", "Charlie");

String firstName = names.stream()
                        .findFirst()
                        .orElse("No Name");

System.out.println(firstName); // Alice

 

 


 

정리

'백엔드 > JAVA' 카테고리의 다른 글

[JAVA] Arrays.sort와 Compator  (1) 2025.01.03
[Java] 맵(Map)  (0) 2024.12.04
[JAVA] 리스트  (0) 2024.11.27
[JAVA] 자료구조와 알고리즘  (0) 2024.11.26