1️⃣ Stream이란? (Java 기준)
1) 개념
컬렉션(또는 배열)의 데이터를 선언형으로 처리하기 위한 데이터 처리 파이프라인
2) 핵심 개념 요약
- 데이터 저장 X → Stream은 데이터를 보관하지 않음
- 함수형 처리 →
filter,map같은 함수 조합
- 지연 연산(Lazy) → 최종 연산이 호출될 때까지 실행 안 됨
- 1회용 → 한 번 사용하면 재사용 불가
- 병렬 처리 가능 →
parallelStream()
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * 10)
.forEach(System.out::println);2️⃣ Stream 처리 구조
데이터 소스
↓
중간 연산 (0개 이상)
↓
최종 연산 (1개, 필수)구분 | 특징 |
중간 연산 | Stream 반환 (체이닝 가능) |
최종 연산 | 결과 반환 또는 실행 후 종료 |
3️⃣ 자주 쓰이는 중간 연산 함수
1) filter(Predicate)
조건에 맞는 요소만 통과
stream.filter(x -> x > 10)✔ Boolean 반환 함수 사용
2) map(Function)
요소를 다른 형태로 변환
stream.map(String::length)
✔ 1 → 1 변환
3) flatMap(Function)
중첩 구조를 평탄화
List<List<Integer>> list = List.of(
List.of(1, 2),
List.of(3, 4)
);
list.stream()
.flatMap(List::stream)
.forEach(System.out::println);✔ List<List<T>> → Stream<T>
4) distinct()
중복 제거 (
equals 기준)stream.distinct()
5) sorted() / sorted(Comparator)
정렬
stream.sorted() stream.sorted(Comparator.reverseOrder())
6) limit(n) / skip(n)
개수 제한 / 건너뛰기
stream.limit(5)
stream.skip(3)4️⃣ 자주 쓰이는 최종 연산 함수
1) forEach(Consumer)
각 요소에 대해 동작 수행
stream.forEach(System.out::println);
⚠ 반환값 없음
2) collect(Collector)
Stream → 컬렉션 변환
List<String> result = stream.collect(Collectors.toList());
자주 쓰는 예:
Collectors.toSet()
Collectors.toMap(k -> k.getId(), v -> v)
Collectors.joining(", ")3) reduce(BinaryOperator)
요소를 하나의 값으로 축소
int sum = stream.reduce(0, Integer::sum);4) count()
요소 개수
long cnt = stream.count();5) anyMatch / allMatch / noneMatch
조건 검사
stream.anyMatch(x -> x > 100);
stream.allMatch(x -> x > 0);
stream.noneMatch(x -> x < 0);6) findFirst() / findAny()
요소 하나 찾기 (Optional 반환)
Optional<Integer> value = stream.findFirst();
5️⃣ Stream 사용 시 자주 하는 패턴
1) 컬렉션 필터링 + 변환
List<String> names = users.stream() .filter(u -> u.isActive()) .map(User::getName) .toList();
2) 합계 / 평균
int total =
orders.stream()
.mapToInt(Order::getPrice)
.sum();3) 그룹핑
Map<String, List<User>> byRole = users.stream() .collect(Collectors.groupingBy(User::getRole));
6️⃣ Stream 사용 시 주의점
1) ⚠️ 부작용(side effect) 최소화
// ❌ 지양
stream.forEach(x -> list.add(x));2) ⚠️ Stream 재사용 불가
Stream<Integer> s = list.stream();
s.count();
s.forEach(...); // 예외 발생3) ⚠️ 단순 반복은 for-loop이 더 명확한 경우도 있음
7️⃣ 실습
1) 가공
C:\workspace\spring_lab\skillapp\src\main\java\ex04\StreamEx01.java
package ex04;
import java.util.List;
/**
* Stream : 임시 개울 (임시 수도관)
*/
public class StreamEx01 {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4);
// 1. 가공
List<Integer> newList = list.stream() // 개울에 던지기
.map(i -> i * 2) // 가공 or 연산 (N번) : 중간 연산
.toList(); // 수집
// for문으로 출력
newList.stream().forEach(i -> {
System.out.println(i);
});
}
}
Stream은 중간 연산을 여러 번 할 수 있다!
2) 필터
C:\workspace\spring_lab\skillapp\src\main\java\ex04\StreamEx01.java
package ex04;
import java.util.List;
/**
* Stream : 임시 개울 (임시 수도관)
*/
public class StreamEx01 {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4);
// 2. filter
List<Integer> newList2 = list.stream()
.map(i -> i+1)
.peek(i -> System.out.println(i)) // 한 줄만 적으면 중괄호도 생략 가능
.filter(i -> i < 3)
.toList();
}
}

package ex04;
import java.util.List;
/**
* Stream : 임시 개울 (임시 수도관)
*/
public class StreamEx01 {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4);
// 2. filter
List<Integer> newList2 = list.stream()
.map(i -> i+1)
.peek(i -> System.out.println(i)) // 한 줄만 적으면 중괄호도 생략 가능
.filter(i -> i < 3)
.peek(i -> System.out.println(i)) // 두번째 peek만 작동
.toList();
}
}
peek 은 중간과정 확인용!!
확인했으면 주석처리
package ex04;
import java.util.List;
/**
* Stream : 임시 개울 (임시 수도관)
*/
public class StreamEx01 {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4);
// 2. filter
List<Integer> newList2 = list.stream()
.map(i -> i+1)
.peek(i -> System.out.print(i + " ")) // 한 줄만 적으면 중괄호도 생략 가능
.filter(i -> i < 3)
.toList();
System.out.println();
for (Integer i : newList2) {
System.out.print(i + " ");
}
}
}

3) Max
C:\workspace\spring_lab\skillapp\src\main\java\ex04\StreamEx01.java
package ex04;
import java.util.List;
/**
* Stream : 임시 개울 (임시 수도관)
*/
public class StreamEx01 {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4);
// 3. Max
int maxNum = list.stream()
.mapToInt(i -> i)
.max()
.getAsInt();
System.out.println(maxNum);
}
}
4) limit
C:\workspace\spring_lab\skillapp\src\main\java\ex04\StreamEx01.java
package ex04;
import java.util.List;
/**
* Stream : 임시 개울 (임시 수도관)
*/
public class StreamEx01 {
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3, 4);
// 4. limit
List<Integer> newList4 = list.stream()
.limit(2)
.peek(i -> System.out.print(i + " "))
.toList();
}
}
5) flatMap
C:\workspace\spring_lab\skillapp\src\main\java\ex04\StreamEx02.java
package ex04;
import java.util.List;
public class StreamEx02 {
public static void main(String[] args) {
// [ [1, 2, 3] , [4, 5] , [6, 7, 8, 9] ]
List<List<Integer>> matrix = List.of(
List.of(1, 2, 3),
List.of(4, 5),
List.of(6, 7, 8, 9)
);
// [ [1,2,3], [4,5], [6,7,8,9] ]
// [1,2,3], [4,5], [6,7,8,9]
// 1,2,3 4,5 6,7,8,9
// 1,2,3,4,5,6,7,8,9
// [1,2,3,4,5,6,7,8,9]
List<Integer> newList = matrix.stream()
.flatMap(list -> list.stream())
.toList();
for (Integer i : newList){
System.out.print(i + " ");
}
}
}
package ex04;
import java.util.List;
public class StreamEx02 {
public static void main(String[] args) {
// [ [1, 2, 3] , [4, 5] , [6, 7, 8, 9] ]
List<List<Integer>> matrix = List.of(
List.of(1, 2, 3),
List.of(4, 5),
List.of(6, 7, 8, 9)
);
// [ [1,2,3], [4,5], [6,7,8,9] ]
// [1,2,3], [4,5], [6,7,8,9]
// 1,2,3 4,5 6,7,8,9
// 1,2,3,4,5,6,7,8,9
// [1,2,3,4,5,6,7,8,9]
List<Integer> newList = matrix.stream()
.flatMap(list -> list.stream())
.filter(i -> i > 5)
.toList();
for (Integer i : newList){
System.out.print(i + " ");
}
}
}
6) 적용
C:\workspace\spring_lab\skillapp\src\main\java\ex01\CopyEx04.java
package ex01;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
class Board { // 1:N의 관계에서 Board가 1
private int id;
private String title;
private String content;
private List<Reply> replies = new ArrayList<>();
}
@Data
class Reply { // 1:N의 관계에서 Reply는 N
private int id;
private String comment;
}
@Data
class DetailDTO {
private int id;
private String title;
private String content;
private List<String> comments = new ArrayList<>();
public DetailDTO(Board board) {
this.id = board.getId();
this.title = board.getTitle();
this.content = board.getTitle();
this.comments = board.getReplies().stream()
.map(i -> i.getComment())
.limit(2)
.toList();
// for (int i = 0; i < board.getReplies().size(); i++) {
// this.comments.add(board.getReplies().get(i).getComment());
// }
// for문은 복잡! stream이 보기 편함! -> 그래서 stream 배울 것
// for (Reply reply : board.getReplies()) {
// // if (id < 3)
// if (reply.getId() < 3) {
// this.comments.add(reply.getComment());
// }
// // this.comments.add(reply.getComment());
// }
}
}
public class CopyEx04 {
public static void main(String[] args) {
// 3. 클래스로 넘기기
Reply r1 = new Reply();
r1.setId(1);
r1.setComment("댓글1");
Reply r2 = new Reply();
r2.setId(2);
r2.setComment("댓글2");
Reply r3 = new Reply();
r3.setId(3);
r3.setComment("댓글3");
Board board = new Board();
board.setId(1);
board.setTitle("제목1");
board.setContent("내용1");
board.setReplies(List.of(r1, r2, r3));
DetailDTO detailDTO = new DetailDTO(board);
System.out.println(detailDTO);
}
}
Share article