스트림(중간 처리와 최종처리)

 

 

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

 

스트림 파이프라인

 

 

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는 보통 두 가지 형태로 사용된다.

  1. 초깃값과 누적 함수를 사용: 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
    }
}

 

  1. 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

+ Recent posts