[JAVA] 16. Stream

최재원's avatar
Jun 11, 2025
[JAVA] 16. Stream

공부용 코드

코드 결과
notion image
map
notion image
notion image
filter
notion image
notion image
count, sort, distinct
notion image
notion image

 
notion image
mapToInt, sum, min, max, average
notion image
notion image
groupyby
notion image
notion image
코드
package ex02; import lombok.Data; import java.util.Arrays; import java.util.Comparator; import java.util.stream.Collectors; public class StEx01 { public static void main(String[] args) { var list = Arrays.asList(1, 2, 3, 4, 5); Cart c1 = new Cart(1, "바나나", 1000); Cart c2 = new Cart(2, "바나나", 1000); Cart c3 = new Cart(3, "딸기", 2000); Cart c4 = new Cart(4, "사과", 3000); var cartList = Arrays.asList(c1, c2, c3, c4); // 1. map (가공) var new11 = list.stream().map(i -> i * 2).toList(); System.out.println(new11); var new12 = list.stream() .map(i -> i * 2) .filter(i -> i != 10) .toList(); System.out.println(new12); // 2. filter (검색, 삭제) var new21 = list.stream() .filter(i -> i < 3) .toList(); System.out.println(new21); // 3. count(개수), sort(정렬), distinct(중복제거) var new31 = list.stream() .sorted(Comparator.reverseOrder()) .map(i -> i / 3) .distinct() .count(); System.out.println(new31); // 4. mapToInt, sum, min, max, average var new41 = cartList.stream() // 1. 물가에 던져진 cart 4개 .mapToInt(cart -> cart.getPrice()) // 2. 물가에 던져진 Integer 4개 .min(); System.out.println(new41); // 5. groupby [key=[c1, c2], key=[c3], key=[c4]] var new51 = cartList.stream() .collect(Collectors.groupingBy(cart -> cart.getName())) .entrySet() .stream() .map(en -> en.getValue()) .toList(); System.out.println(new51); } @Data static class Cart { private int id; private String name; private int price; public Cart(int id, String name, int price) { this.id = id; this.name = name; this.price = price; } } }
 
 
 
Java의 Stream API는 Java 8에서 도입된 기능으로, 컬렉션 데이터를 다루는 데 있어 더 효율적이고 선언적인 방법을 제공합니다. Stream API는 컬렉션에 저장된 데이터를 처리(필터링, 정렬, 변환 등)하는데 유용하며, 함수형 프로그래밍 스타일을 지원합니다.
기존의 입출력 스트림과는 전혀 다른 개념이니 혼동하지 않도록 합니다.

주요 개념

  1. Stream:
      • 데이터의 순차적인 흐름을 나타냅니다. 컬렉션에서 데이터를 추출하여 스트림을 생성할 수 있습니다.
  1. 중간 연산 (Intermediate Operations):
      • 스트림을 변환하지만, 결과를 최종적으로 반환하지 않는 연산입니다. 중간 연산은 항상 또 다른 스트림을 반환하며, 이는 체이닝(chaining)될 수 있습니다. 예: filter, map, sorted.
  1. 최종 연산 (Terminal Operations):
      • 스트림을 처리하고 결과를 반환합니다. 최종 연산이 호출되면 스트림의 데이터가 소비되며, 이후에 스트림을 다시 사용할 수 없습니다. 예: forEach, collect, reduce.
 
 
 
 

예제 1: Count

 
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); List<String> r1 = names.stream().filter(name -> name.length() > 3).toList(); r1.forEach(s -> System.out.println(s)); Long r2 = names.stream().filter(name -> name.length() > 3).count(); System.out.println(r2);
 
  • 설명:
    • filter: 이름의 길이가 3보다 큰 요소만 필터링합니다.
    • toList: 필터링된 결과를 리스트로 반환합니다.
    • forEach: 결과를 하나씩 출력합니다.
    • count: 필터링된 요소의 개수를 세고 출력합니다.
  • 결과:
    • 필터링된 리스트 출력: "Alice", "Charlie", "David"
    • 필터링된 요소의 개수 출력: 3
 
 

예제 2: Sort

 
List<Integer> nums = Arrays.asList(5, 3, 1, 4, 2, 5); // 정렬을 한 뒤, 중복을 제거하고, 반복문으로 출력한다. nums.stream().sorted().distinct().forEach(integer -> System.out.println(integer));
 
  • 설명:
    • sorted: 리스트의 요소를 오름차순으로 정렬합니다.
    • distinct: 중복된 요소를 제거합니다.
    • forEach: 정렬되고 중복이 제거된 요소를 하나씩 출력합니다.
  • 결과:
    • 출력: 1, 2, 3, 4, 5
 
 

예제 3: Map

 
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David"); List<String> newNames = names.stream().map(name -> name.toLowerCase()) .filter(name -> name.length() > 3) .toList(); newNames.forEach(name -> System.out.println(name));
 
  • 설명:
    • map: 각 이름을 소문자로 변환합니다.
    • filter: 이름의 길이가 3보다 큰 요소만 필터링합니다.
    • toList: 필터링된 결과를 리스트로 반환합니다.
    • forEach: 결과를 하나씩 출력합니다.
  • 결과:
    • 출력: "alice", "charlie", "david"
 
 

예제 4: Group

 
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "anna"); // 리턴 타입 : Map<Character, List<String>> // 최근 버전은 var로 모든 형을 대체해서 쓸 수 있게 패치되었다. var groupData = names.stream() .map(name -> name.toUpperCase()) .collect(Collectors.groupingBy(name -> name.charAt(0))); System.out.println(groupData);
 
  • 설명:
    • map: 각 이름을 대문자로 변환합니다.
    • collect: 이름의 첫 글자를 기준으로 그룹화하여 Map으로 반환합니다.
    • Collectors.groupingBy: 그룹화를 수행하는 수집기(collector)를 사용합니다.
  • 결과:
    • 출력: {A=[ALICE, ANNA], B=[BOB], C=[CHARLIE], D=[DAVID]}
 
 

예제 5: Reduce (조인)

 
List<Integer> nums = Arrays.asList(1, 2, 3, 4); int sum1 = nums.stream().mapToInt(x -> x).sum(); System.out.println(sum1); int sum2 = nums.stream().reduce(5, (prev, next) -> { System.out.println("prev : " + prev); System.out.println("next : " + next); System.out.println("----------"); return prev + next; }); System.out.println(sum2);
 
  • 설명:
    • mapToIntsum: 스트림의 모든 요소를 정수형으로 변환하고 합계를 계산합니다.
    • reduce: 초기값 5를 가지고, 스트림의 모든 요소를 더하여 최종 합계를 계산합니다. 중간 값(prevnext)을 출력합니다.
  • 결과:
    • sum1: 10 (1 + 2 + 3 + 4)
    • sum2: 15 (5 + 1 + 2 + 3 + 4)
 
 

추가 주요 개념과 기능

기능
설명
예제
entrySet
Map 객체를 순회할 때 사용. key, value 모두 접근할 때 필요
map.entrySet().forEach(e -> System.out.println(e.getKey() + " : " + e.getValue()));
groupingBy
특정 조건으로 그룹핑할 때 사용 (Collectors.groupingBy)
collect(Collectors.groupingBy(x -> x.charAt(0)))
distinct
스트림에서 중복을 제거
stream().distinct()
limit
스트림의 일부만 추출
stream().limit(5) → 앞 5개만 가져오기
skip
앞의 일부 요소를 건너뛰기
stream().skip(3) → 앞 3개 건너뛰기
peek
중간에 디버깅용으로 값 찍을 때 사용 (forEach 아님)
stream().peek(x -> System.out.println(x))
flatMap
스트림 안에 스트림이 있을 때 평탄화 (2차원 → 1차원)
stream().flatMap(List::stream)
anyMatch
하나라도 조건에 맞으면 true
stream().anyMatch(x -> x > 5)
allMatch
모두 조건에 맞아야 true
stream().allMatch(x -> x > 5)
noneMatch
모두 조건에 안 맞아야 true
stream().noneMatch(x -> x > 5)
findFirst
첫 번째 요소 가져오기 (Optional)
stream().findFirst()
findAny
병렬 스트림 등에서 아무 요소나 빠르게 가져오기
parallelStream().findAny()
min/max
최소값, 최대값 찾기
stream().min(Comparator.naturalOrder())

간단 예시 추가

1. limit / skip

java 복사 List<Integer> nums = Arrays.asList(1,2,3,4,5,6,7,8,9,10); nums.stream().skip(3).limit(5).forEach(System.out::println); // 출력: 4 5 6 7 8

2. peek (디버깅용)

java 복사 List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream() .peek(name -> System.out.println("Before filter: " + name)) .filter(name -> name.length() > 3) .peek(name -> System.out.println("After filter: " + name)) .forEach(System.out::println);

3. flatMap

java 복사 List<List<Integer>> listOfLists = Arrays.asList( Arrays.asList(1, 2), Arrays.asList(3, 4), Arrays.asList(5, 6) ); listOfLists.stream() .flatMap(List::stream) .forEach(System.out::println); // 출력: 1 2 3 4 5 6

4. anyMatch / allMatch / noneMatch

java 복사 List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5); boolean anyAbove3 = nums.stream().anyMatch(n -> n > 3); // true boolean allAbove0 = nums.stream().allMatch(n -> n > 0); // true boolean noneAbove10 = nums.stream().noneMatch(n -> n > 10); // true System.out.println(anyAbove3); System.out.println(allAbove0); System.out.println(noneAbove10);

요약

  • 데이터 조작: filter, map, flatMap
  • 데이터 흐름 제어: limit, skip, peek
  • 결과 수집: collect, groupingBy
  • 검사: anyMatch, allMatch, noneMatch
  • 요소 찾기: findFirst, findAny
  • 최댓값, 최솟값: max, min
  • 디버깅용: peek
  • 중복 제거: distinct
  • Map 처리: entrySet
 
Share article

jjack1