stream() 개념을 확실히 하고 용례를 정리한다
| 방식 | 대상 | 예시 |
|---|---|---|
| .stream() | 컬렉션 (List,Set,Map 등) | list.stream() |
| Arrays.stream() | 배열(int[], String[] 등) | Arrays.stream(arr) |
.stream() - 컬렉션에서 사용List<Integer> list = List.of(1, 2, 3, 4, 5);
int sum = list.stream()
.filter(n -> n % 2 == 0)
.mapToInt(Integer::intValue)
.sum();
Collection 인터페이스에 .stream() 메서드가 정의되어 있기 때문에, List/Set 등 컬렉션 계열은 .stream()을 통해 바로 호출 가능Arrays.stream() - 배열에서 사용int[] arr = {1, 2, 3, 4, 5};
int sum = Arrays.stream(arr)
.filter(n -> n % 2 == 0)
.sum();
Collection이 아니므로 .stream() 보유하지 않음. 대신 Arrays 유틸 클래스의 정적 메서드를 사용함int[]에 Arrays.stream()을 쓰면 자동으로 IntStream이 반환되어 .sum(), .average() 등을 바로 쓸 수 있어서 편리합니다.Collection 인터페이스란 Java에서 "여러 객체를 담는 자료구조들의 공통 규격"
계층 구조로 보기
Iterable
└── Collection ← 여기
├── List (순서 O, 중복 O)
│ ├── ArrayList
│ └── LinkedList
├── Set (순서 X, 중복 X)
│ ├── HashSet
│ └── TreeSet
└── Queue
└── LinkedList
Map의 경우 Collection을 상속하지 않는 별개의 인터페이스Collection 인터페이스에는 .stream() 메서드가 정의되어 있음ArrayList, HashSet 등 모든 컬렉션에서 호출 가능// 모두 Collection을 구현 → .stream() 사용 가능
new ArrayList<>().stream();
new HashSet<>().stream();
new LinkedList<>().stream();
// ❌ 배열에 .stream() 직접 호출 → 불가
int[] arr = {1, 2, 3};
arr.stream(); // 컴파일 에러!
// ✅ 배열 → Stream으로 변환하려면
Arrays.stream(arr) // int[] → IntStream
// String[] 도 마찬가지
String[] strArr = {"a", "b", "c"};
Arrays.stream(strArr).forEach(System.out::println);
list.stream()
.filter(n -> n > 3) // 중간 연산 - 아직 실행 안 됨!
.map(n -> n * 2) // 중간 연산 - 아직 실행 안 됨!
.collect(...) // 최종 연산 - 여기서 한 번에 실행됨
collect(), forEach(), count(), sum(), findFirst(), anyMatch() 등Stream<Integer> stream = list.stream();
stream.filter(n -> n > 3).collect(toList()); // ✅ 정상
stream.map(n -> n * 2).collect(toList()); // ❌ 에러! 이미 소비된 스트림
.stream()을 통해 새로 호출해야 합니다.List<List<Integer>> nested = List.of(
List.of(1, 2),
List.of(3, 4)
);
// map → Stream<List<Integer>> (리스트가 그대로 원소)
nested.stream()
.map(inner -> inner) // [[1,2], [3,4]]
// flatMap → Stream<Integer> (펼쳐서 하나의 스트림으로)
nested.stream()
.flatMap(inner -> inner.stream()) // [1, 2, 3, 4]
map은 1:1 변환, flatMap은 중첩 구조를 펼칠 때 사용합니다.Stream<Integer>int[] arr = {1, 2, 3};
// Arrays.stream(int[]) → IntStream (기본형 특화 스트림)
Arrays.stream(arr).sum(); // ✅ 바로 사용 가능
Arrays.stream(arr).average(); // ✅
// Stream<Integer>는 sum() 없음
list.stream().sum(); // ❌ 컴파일 에러
// Stream<Integer> → IntStream 변환
list.stream()
.mapToInt(Integer::intValue) // 여기서 IntStream으로 변환
.sum(); // ✅
IntStream, LongStream, DoubleStream은 기본형에 특화된 스트림으로, .sum(), .average(), .min(), .max() 등을 바로 쓸 수 있습니다.
// List로 수집
List<Integer> result = stream.collect(Collectors.toList());
// Map으로 수집 (코테에서 자주 등장)
Map<String, Integer> map = stream.collect(
Collectors.toMap(
s -> s, // key
s -> s.length() // value
)
);
// 그룹핑 (빈도수 문제 등에서 유용)
Map<Integer, List<String>> grouped = stream.collect(
Collectors.groupingBy(String::length)
);
// 빈도수 카운팅
Map<String, Long> freq = stream.collect(
Collectors.groupingBy(s -> s, Collectors.counting())
);
list.stream().sorted(); // 오름차순 (기본)
list.stream().sorted(Comparator.reverseOrder()); // 내림차순
// 객체 정렬
list.stream().sorted(Comparator.comparing(Person::getAge)); // 나이 오름차순
list.stream().sorted(Comparator.comparing(Person::getAge).reversed()); // 나이 내림차순
// 다중 조건 정렬
list.stream().sorted(
Comparator.comparing(Person::getAge)
.thenComparing(Person::getName) // 나이 같으면 이름순
);