Java

[Java] Stream

KJihun 2023. 6. 21. 13:55
728x90

스트림(Stream)은 데이터를 작은 조각으로 나누어 순차적으로 처리하는 방식이다.

예를 들어, 유튜브를 생각해보자.
우리가 영상을 볼 때, 처음부터 끝까지 파일을 한 번에 받아오는 게 아니라, 작은 단위(조각)로 조금씩 받아오면서 영상이 재생된다.

만약 중간에 분 단위로 스킵하면 영상이 잠깐 멈추는(버퍼링) 이유는, 해당 구간의 조각 데이터를 아직 못 받았기 때문이다.

이처럼 스트리밍은 전체 데이터를 한꺼번에 가져오지 않아도 실시간으로 처리할 수 있어서, 메모리도 효율적으로 사용할 수 있다.

 

 

⚙️ 스트림의 특징

 

  • 원본 데이터를 변경하지 않는다
    • 스트림은 원본 데이터를 건드리지 않고, 복사된 데이터를 기준으로 작업한다.
  • 휘발성이다
    • 스트림은 한 번 사용하면 다시 사용할 수 없다.
      (재사용하려면 새 스트림을 만들어야 함)
  • 컬렉션에서 스트림을 만들 수 있다
    • 리스트, 배열 등 다양한 컬렉션은 .stream()이나 Stream.of()로 쉽게 스트림을 생성할 수 있다.

 

 

Stream은 각 단계('생성 -> 가공 -> 결과')를 거친 후 생성된다. 

 

 

📌 스트림의 처리 단계

 

1. 생성

Collection의 Stream 생성

앞서 말했듯이, stream은 collection에 포함되어 있어서 점(.)을 사용하여 손쉽게 호출이 가능하다.

List<String> list = Arrays.asList("Apple", "Banana", "Orange");
Stream<String> listStream = list.stream();

 

배열의 Stream 생성

배열은 Stream.of를 사용하여 생성한다.

String[] fruits = {"Apple", "Banana", "Orange"};
Stream<String> stringStream = Stream.of(fruits);

 


 

2. 가공 (중간 연산)

 

중간연산을 사용하여 원하는 결과를 출력할 수 있도록 유도한다.

중간연산은 함수형 인터페이스를 사용하며 여러 중간연산을 연결시켜 사용하는 메서드 체이닝이 가능하다.

✅ filter() - 조건 걸러내기

Stream<String> stream = 
	fruits.stream()
    .filter(name -> name.contains("Apple"));

 

✅ map() - 데이터 변환

Stream<String> stream = 
	fruits.stream()
    .map(s -> s.toUpperCase());

 

Sorted() - 정렬

// 오름차순 정렬
Stream<String> stream = fruits.stream().sorted();
  
// 내림차순 정렬
Stream<String> stream = fruits.stream().sorted(Comparator.reverseOrder());

 

✅ distinct() – 중복 제거

Stream<String> stream = fruits.stream().distinct();

 


 

 

3. 결과 (최종 연산)

 

✅ 값 계산하기 (min, max, sum, count 등)

                List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

                // 총합
                int sum = numbers.stream().reduce(0, (a, b) -> a + b);
                System.out.println("합: " + sum);
                
                
                // ....

                // 포함된 요소의 갯수
                long count = numbers.stream().count();
                System.out.println("갯수: " + count);

 

 

✅ collect() – 결과 수집

 

🔹 리스트로 수집

List<String> result = fruits.stream().collect(Collectors.toList());

 

🔹 맵으로 수집

Map<String, Integer> map = fruits.stream()
    .collect(Collectors.toMap(Fruit::getName, Fruit::getPrice));

 

🔹 문자열로 결합 (joining())

String result = fruits.stream()
    .map(Fruit::getName)
    .collect(Collectors.joining(", ", "<", ">"));

 

🔹 합계, 평균 등

int total = fruits.stream().collect(Collectors.summingInt(Fruit::getPrice));
double avg = fruits.stream().collect(Collectors.averagingInt(Fruit::getPrice));

 

🔹 요약 통계 (summarizingInt())

IntSummaryStatistics stats = fruits.stream()
    .collect(Collectors.summarizingInt(Fruit::getPrice));

 

✅ groupingBy() – 그룹으로 묶기

Map<Integer, List<Fruit>> grouped = fruits.stream()
	.collect(Collectors.groupingBy(Fruit::getPrice));
 
 

✅ partitioningBy() – 조건에 따라 두 그룹으로 나누기

Map<Boolean, List<Fruit>> partitioned = fruits.stream()
	.collect(Collectors.partitioningBy(fruit -> fruit.getPrice() > 1000));

 

 

✅ match() – 조건 만족 여부 확인

List<String> names = Arrays.asList("Eric", "Elena", "Java");

boolean any = names.stream().anyMatch(name -> name.contains("a")); 
boolean all = names.stream().allMatch(name -> name.length() > 3); 
boolean none = names.stream().noneMatch(name -> name.endsWith("s"));

 

✅ forEach() – 하나씩 처리

names.stream().forEach(System.out::println);
 

 

 

'Java' 카테고리의 다른 글

Servlet, JSP  (0) 2025.04.02
Comparable VS Comparator  (0) 2025.03.02
오버로딩(Overloading)과 오버라이딩(Overriding)  (0) 2023.06.09
모던 자바 알아보기(람다, 스트림, Optional)  (0) 2023.05.30
쓰레드의 상태  (0) 2023.05.30