자바 - Stream

Psj·2025년 2월 20일

F-lab

목록 보기
1/197

Stream이란?

📌 Stream은 데이터의 흐름을 다루는 API

  • 데이터를 저장하는 것이 아니라, 데이터를 읽고 처리하는 흐름을 제공
  • 한 번 사용하면 다시 사용할 수 없음 (소모성, 일회성)
  • List, Set, Map, Array 등의 데이터 구조에서 사용 가능

Stream API 기본 구조

List<String> list = Arrays.asList("apple", "banana", "cherry");

// 1. 스트림 생성 → 2. 중간 연산(filter, map 등) → 3. 최종 연산(collect, forEach 등)
List<String> result = list.stream()
                          .filter(s -> s.startsWith("b")) // 'b'로 시작하는 요소만 선택
                          .map(String::toUpperCase)       // 대문자로 변환
                          .sorted()                       // 정렬
                          .collect(Collectors.toList());  // 리스트로 변환

System.out.println(result); // 출력: [BANANA]

스트림 생성방법 (생성-중간연산-최종연산)

1. 스트림으로 변환 또는 스트림 생성

1. 컬렉션(List, Set)에서 스트림으로 변환

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream(); // 일반 스트림

2. 배열에서 스트림으로 변환

String[] arr = {"A", "B", "C"};
Stream<String> stream = Arrays.stream(arr);

3. Stream.of() 로 생성

Stream<String> stream = Stream.of("a", "b", "c");

4. 숫자형 스트림(IntStream, LongStream, DoubleStream)

IntStream intStream = IntStream.range(1, 6); // 1~5

5. 빈 스트림 생성

Stream<String> emptyStream = Stream.empty();

2. 중간 연산 (Intermediate Operations)

✅ 1) filter(Predicate<T\>) - 조건에 맞는 요소만 필터링

Predicate<T> 함수형 인터페이스는 파라미터를 받아 참거짓으로 리턴하는 기능을 가짐

List<String> list = Arrays.asList("apple", "banana", "cherry", "blueberry");

List<String> filteredList = list.stream()
                                .filter(s -> s.startsWith("b"))
                   .collect(Collectors.toList());

System.out.println(filteredList); // 출력: [banana, blueberry]

✅ 2) map(Function<T, R>) - 요소 변환

Function<T, R> 함수형 인터페이스는 파라미터를 받아 조건에 맞게 변형후 변형된 값을 리턴하는 기능을 가짐

List<String> names = Arrays.asList("john", "peter", "anna");

List<String> upperCaseNames = names.stream()
                                   .map(String::toUpperCase)
                            .collect(Collectors.toList());

System.out.println(upperCaseNames); // 출력: [JOHN, PETER, ANNA]

✅ 3) sorted() - 정렬

List<Integer> numbers = Arrays.asList(5, 2, 9, 1, 3);

List<Integer> sortedNumbers = numbers.stream()
                                     .sorted()
                                     .collect(Collectors.toList());

System.out.println(sortedNumbers); // 출력: [1, 2, 3, 5, 9]

✅ 4) distinct() - 중복 제거

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4);

List<Integer> distinctNumbers = numbers.stream()
                                       .distinct()
                                       .collect(Collectors.toList());

System.out.println(distinctNumbers); // 출력: [1, 2, 3, 4]

✅ 5) limit(n), skip(n) - 개수 제한 및 건너뛰기

List<Integer> numbers = Arrays.asList(10, 20, 30, 40, 50);

List<Integer> limitedNumbers = numbers.stream()
                                      .limit(3) // 처음 3개만 선택
                                      .collect(Collectors.toList());

List<Integer> skippedNumbers = numbers.stream()
                                      .skip(2) // 처음 2개 건너뛰기
                                      .collect(Collectors.toList());

System.out.println(limitedNumbers); // 출력: [10, 20, 30]
System.out.println(skippedNumbers); // 출력: [30, 40, 50]

3. 최종연산

✅ 1) collect(Collectors.toList()) - 결과를 리스트로 변환

List<String> result = list.stream()
                          .filter(s -> s.length() > 3)
                          .collect(Collectors.toList());

✅ 2) forEach() - 모든 요소 출력

list.stream().forEach(System.out::println);

✅ 3) count() - 요소 개수 반환

long count = list.stream().count();

✅ 4) anyMatch(), allMatch(), noneMatch() - 조건 검사

boolean hasApple = list.stream().anyMatch(s -> s.equals("apple")); // 하나라도 만족하면 true
boolean allStartWithA = list.stream().allMatch(s -> s.startsWith("a")); // 모두 만족하면 true
boolean noneStartWithZ = list.stream().noneMatch(s -> s.startsWith("z")); // 하나도 만족하지 않으면 true

✅ 5) reduce() - 누적 연산

int sum = numbers.stream().reduce(0, Integer::sum); // 모든 숫자 더하기
System.out.println(sum); // 출력: 합계 값

📌 :: (메서드 참조) 연산자 설명

링크 확인

 public List<CourseInfoDto> getCourseDayOfWeek(DayOfWeek dayOfWeek) {
    // TODO: 과제 구현 부분
    List<Course> courses = courseRepository.getCourseDayOfWeek(dayOfWeek);
    return courses.stream().map(CourseInfoDto::new).toList();
  }

Stream<Integer> 와 IntStream의 차이

1. 기본 개념

  • Stream<Integer>: Stream<T>의 제네릭 버전으로, Integer 객체를 요소로 가지는 스트림.
  • IntStream: 기본형 int 값을 다루는 특수한 스트림.

3. 사용법 차이

Stream<Integer>

  • Integer 객체를 다루므로 Stream<Integer>에서 제공하는 일반적인 Stream 메서드를 사용할 수 있음.
  • 하지만 sum(), average() 같은 숫자 연산을 하려면 mapToInt() 등을 사용하여 IntStream으로 변환해야 함.
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
int sum = integerStream.mapToInt(Integer::intValue).sum();  // IntStream으로 변환 후 합계 계산
System.out.println(sum); // 15

IntStream

  • sum(), average(), max(), min() 같은 숫자 연산 메서드를 바로 제공함.
  • boxed()를 사용하면 Stream<Integer>로 변환할 수 있음.
IntStream intStream = IntStream.of(1, 2, 3, 4, 5);
int sum = intStream.sum(); // 바로 합계 계산 가능
System.out.println(sum); // 15

4. 생성 방식

Stream<Integer> 생성

Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);

IntStream 생성

IntStream intStream1 = IntStream.of(1, 2, 3, 4, 5);
IntStream intStream2 = IntStream.range(1, 6);  // 1부터 5까지 (6은 포함되지 않음)
IntStream intStream3 = IntStream.rangeClosed(1, 5); // 1부터 5까지 포함

5. 변환 방법

Stream<Integer> → IntStream

Stream<Integer> integerStream = Stream.of(1, 2, 3);
IntStream intStream = integerStream.mapToInt(Integer::intValue);

IntStream → Stream<Integer>

IntStream intStream2 = IntStream.of(1, 2, 3);
Stream<Integer> boxedStream = intStream2.boxed();
profile
Software Developer

0개의 댓글