스트림(중간 처리와 최종처리)
스트림은 하나이상이 연결될 수 있다고 하였는데 오리지널 스트림과 중간 스트림 최종처리를 하는 스트림 등등 여러개의 스트림이 연결되어 하나의 스트림 파이프 라인을 형성할 수 있다.

1. 오리지널 스트림 (Original Stream)
- 정의: 데이터 소스에서 스트림을 생성하는 첫 단계입니다.
- 예시: 컬렉션(List, Set, Map), 배열(Array), 파일, I/O 채널 등에서 stream() 메서드로 생성할 수 있습니다.
- EX: List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
- Stream<String> nameStream = names.stream(); // 오리지널 스트림 생성
2. 필터링 중간 스트림 (Filtering Intermediate Stream)
- 정의: 오리지널 스트림의 데이터를 특정 조건에 맞게 필터링하여 추출하는 중간 연산입니다.
- 특징: filter() 메서드를 사용하며, 스트림의 각 요소를 조건에 맞춰 걸러냅니다.
- EX : Stream<String> filteredStream = nameStream.filter(name -> name.startsWith("A")); // "Alice"만 남음
3. 매핑 중간 스트림 (Mapping Intermediate Stream)
- 정의: 스트림의 각 요소를 다른 값으로 변환하는 중간 연산입니다.
- 특징: map() 또는 flatMap()을 사용하며, 각각의 요소를 원하는 방식으로 변환하여 새로운 스트림을 만듭니다.
- EX : Stream<Integer> nameLengthStream = nameStream.map(name -> name.length()); // "Alice" -> 5, "Bob" -> 3
4. 집계 처리 (Reduction or Terminal Operation)
- 정의: 중간 연산을 거친 스트림을 최종적으로 하나의 결과로 집계하거나 처리하는 단계입니다.
- 종류: collect(), reduce(), forEach(), count(), sum() 등 다양한 최종 연산 메서드를 사용하여 결과를 생성합니다.
- EX : int totalLength = nameStream.map(name -> name.length()).reduce(0, Integer::sum); // 각 이름 길이의 총합
또 다른 예시 :
class Family {
private String name;
private int age;
public Family(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
} //family 객체
List<Family> list = new ArrayList<>(); // List 선언
list.add(new Family("홍길동", 20));
list.add(new Family("홍무개", 30));
list.add(new Family("홍성천", 40));
Stream<Family> familyStream = list.stream(); //오리지널 스트림
//람다를 이용하여 주입받은 family 객체에서 age 필드를 mapToInt를 통하여 IntStream으로 변환
IntStream ageStream = familyStream.mapToInt( family -> family.getAge() ); // 매핑 처리
double avg = ageStream.average().getAsDouble(); // 평균 계산
메소드 체이닝 패턴을 통하여 간결하게 작성
double avg = list.stream()
.mapToInt(family -> family.getAge())
.average()
.getAsDouble();
중간처리_필터링
오리지널 스트림에서 요소를 걸러내는 필터링이다. 필터링 메서드에서는 distinct()와 filter()가 있다.
| 리턴 타입 | 메서드 | 설명 |
| Stream IntStream LongStream DoubleStream |
distinct() | 중복을 제거한다. |
| filter(Predicate<T>) filter(IntPredicte) filter(LongPredicate) filter(DoublePredicate) |
조건필터링, Predicte 는함수형 인터페이스이므로 람다식으로 작성가능 |
distinct는 요소의 중복을 제거한다.
filter는 매개값으로 주어진 Predicate가 true를 리턴하는 값들만 걸러준다.
public class FilteringExample{
public static void main(String[] args){
List<String> list = new ArrayList<>();
list.add("남궁승현");
list.add("한구");
list.add("김승현");
list.add("김승현");
list.add("최현");
//중복값 제거
list.stream()
.distinct()
.forEach(n -> System.out.println(n));
//결과: 남궁승현, 한구, 김승현, 최현
//이름이 3글자 이상만
list.stream()
.filter(n -> n.length >= 3)
.forEach(n -> System.out.println(n));
//결과: 남궁승현, 김승현, 김승현
}
}
요소 변환 (매핑)
스트림의 각 요소에 대해 특정 함수를 적용하여, 요소의 형태나 값을 변경할 때 사용된다.
map으로 시작하는 메서드는 다른 요소로 변환한 새로운 스트림을 리턴한다.
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 중간 스트림을 사용하여 각 숫자를 제곱으로 변환
List<Integer> squaredNumbers = numbers.stream()
.map(number -> number * number) // 요소 변환
.collect(Collectors.toList()); // 최종 연산
System.out.println(squaredNumbers); // [1, 4, 9, 16, 25]
}
}
public class Main {
public static void main(String[] args){
int[] intArray = { 1,2,3, 4, 5};
//배열에서 intstream으로
IntStream int Stream = Arrays.stream(intArray);
intStream.asDoubleStream().forEach(d -> System.out.println(d)); //int형을 double로 변환해서 출력
//결과: 1.0, 2.0, 3.0, 4.0, 5.0
}
}
flatMap은 스트림의 각 요소를 다수의 요소로 변환하는 데 사용되는 중간 연산이다.
주로 각 요소가 리스트나 배열 같은 컬렉션을 포함하고 있을 때 사용되며, 각 요소를 개별 요소로 **평탄화(flatten)**하여 하나의 스트림으로 합쳐준다.
예를 들어, map은 각 요소를 변환하여 새로운 스트림으로 반환하는 반면, flatMap은 여러 하위 컬렉션을 하나의 평탄한 스트림으로 만들어준다.
public class Main {
public static void main(String[] args) {
List<String> sentences = Arrays.asList("Hello world", "Java streams", "flatMap example");
// flatMap을 사용하여 각 문장을 단어로 분리하여 평탄화
List<String> words = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" "))) // 평탄화 연산
.collect(Collectors.toList()); // 최종 연산
System.out.println(words); // [Hello, world, Java, streams, flatMap, example]
}
}
요소 집계
최종 처리 기능으로 요소들을 카운팅, 평균, 합계 등의 연산을 처리하여 하나의 값으로 산출한다.
스트림이 제공하는 기본 집계 메서드로는
count() : 요소 수
findFirst() : 첫번째 값
max : 최대 값
min : 최소 값
average() : 평균 값
sum() : 합계
등이 있다.
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3, 5, 7, 9, 11);
// 1. reduce()를 사용하여 리스트의 합계 계산
int sum = numbers.stream()
.reduce(0, (accumulator, number) -> accumulator + number);
// 2. count()를 사용하여 요소의 개수 계산
long count = numbers.stream()
.count();
System.out.println("Sum: " + sum); // Sum: 35
System.out.println("Count: " + count); // Count: 5
}
}
reduce는 스트림의 각 요소를 누적하여 하나의 결과로 집계하는 연산이다.
reduce의 기본 구조
reduce는 보통 두 가지 형태로 사용된다.
- 초깃값과 누적 함수를 사용: reduce(초깃값, (accumulator, element) -> { ... })
public class Main {
public static void main(String[] args) {
List<String> words = Arrays.asList("Java", "Stream", "API");
// reduce를 사용하여 문자열을 이어붙이기
String concatenated = words.stream()
.reduce("", (accumulator, word) -> accumulator + word);
System.out.println("Concatenated: " + concatenated); // Concatenated: JavaStreamAPI
}
}
- Optional을 반환하며 누적 함수만 사용하는 경우: reduce((accumulator, element) -> { ... })
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3, 5, 7, 9, 11);
// reduce를 사용하여 최대값 찾기
Optional<Integer> max = numbers.stream()
.reduce((a, b) -> a > b ? a : b);
max.ifPresent(value -> System.out.println("Max: " + value)); // Max: 11
}
}
- 초깃값: 연산이 시작될 때 사용할 기본값.
- accumulator: 현재까지 누적된 결과.
- element: 현재 스트림에서 처리 중인 요소.
'Java' 카테고리의 다른 글
| [JAVA] Comparable, Comparator (1) | 2025.12.13 |
|---|---|
| [JAVA] 리소스로부터 스트림 얻기 (0) | 2025.10.13 |
| [JAVA] 스트림_내부반복자 (0) | 2025.10.13 |
| [JAVA] Daemon Thread와 Thread pool (0) | 2025.10.07 |
| [JAVA] 제네릭 (0) | 2025.10.06 |