Java 중급5

j0yy00n0·2025년 3월 11일

2025.03.10

스트림

Stream

컬렉션(자료구조)에 저장된 엘리먼트(요소)들을 하나씩 순회하면서 처리할 수 있는 기능

  • 람다식과 함께 사용 가능, 컬렉션에 들어있는 데이터에 대한 처리를 간결하게 표현 가능

Stream이 필요한 이유

  • 배열/컬렉션을 함수 여러 개를 사용해서 결과를 쉽게 얻을 수 있다.
  • 람다식을 활용해 코드 양도 줄이고 간결하게 표현도 가능하다.

Stream 구분

  • 생성 : 스트림 생성
  • 가공 : 원하는결과를 만들기 위한 필터링, 매핑, 등의 작업
  • 결과 : 최종 결과를 만들어 내는 작업

데이터들 -> 조건으로 거르기 -> 형태 바꾸기 -> 결과 만들기

Stream 생성

자주 사용하는 배열과 컬렉션 객체에서 stream() 메소드 지원

  • 배열 : 스트림을 생성할 배열을 생성한 후 stream() 사용

    Stream<T> 참조변수명 = Arrays.stream(배열명);
    Stream<T> 참조변수명 = Arrays.stream(배열명, 시작인덱스, 끝인덱스);

  • 컬렉션 : 컬렉션 생성 후 stream() 사용 -> 컬렉션의 경우 일부 메서드 체이닝에서 바로 .stream()을 붙여 사용할 수 있다.

    Stream<T> 참조변수명 = 컬렉션명.stream();

  • 비어있는 스트림 : 요소가 없을 때 사용

  • 문자 관련 스트림

  • 스트림 합치기

기본 타입 스트림 생성

  • range(시작값, 종료값) : 시작값부터 1씩 증가하는 숫자로 종료값 전까지 범위의 스트림 생성
  • rangeClosed(시작값, 종료값) : 시작값부터 1씩 증가하는 숫자로 종료값까지 범위의 스트림 생성
  • Pattern.compile(", "). : 문자열을 나눌 때 컴파일러에서 ,으로 나눔
  • concat() : 두 개의 스트림을 동일 타입 스트림으로 합칠 수 있다.

Stream 가공

스트림에서는 데이터를 가공할 수 있는 메소드를 제공, 해당 메소드들은 Stream을 전달받아 Stream을 반환하므로 연속해서 메소드를 연결할 수 있다.

filter

스트림에서 특정 데이터만 걸러내는 메소드

  • 매개변수로 받는 Predicate는 boolean을 리턴하는 함수형 인터페이스

    Stream filter(Predicate<? super T> predicate);
    스트림변수명.filter(조건).

map

스트림에 들어있는 데이터를 특정 람다식을 통해 데이터를 가공하고 새로운 스트림에 담아주는 역할

Stream map(Function<? super T, ? extends R> mapper);
스트림변수명.filter(조건).map(추가가공).

flatMap

중첩 구조를 한 단계 제거하고 단일 컬렉션으로 만들어준다. -> 플래트닝(flattening)

컬렉션명.stream().flatMap(Collection::stream).collect(Collectors.to컬렉션());

sorted

인자가 없이도 호출이 가능한데, 인자가 없으면 오름차순으로 자동 정렬

Stream sorted();
Stream sorted(Comparator<? super T> comparator);

Stream 결과

가공된 스트림을 통해 결과를 만들어 내는 작업

  • 데이터를 필터링하고 가공한 뒤에 출력하기 위해서 진행하는 작접
  • Calculating, Reduction, Collecting, Matching이 포함
  • .forEach() + 람다 표현식 : 메서드 참조(::)를 이용하여 반복문

Calculating

최소/최대/총합/평균 등 과 같은 결과

Reduction

reduce() 라는 메소드는 스트림에 있는 데이터들의 총합을 계산

Optional reduce(BinaryOperator accumulator);

Collecting

collect() 는 Collector 타입을 받아서 처리하는데, 해당 메소드를 통해 컬렉션을 출력으로 받을 수 있다.
collect() 메소드는 Collector 객체에서 제공하는 정적 메소드를 사용할 수 있다.

Matching

boolean anyMatch(Predicate<? super T> predicate); // 하나라도 조건을 만족하는 값이 있는지
boolean allMatch(Predicate<? super T> predicate); // 모든 조건을 만족하는지
boolean noneMatch(Predicate<? super T> predicate); // 모든 조건을 만족하지 않는지


예시

List<String> names = List.of("kim", "lee", "park", "kang");

List<String> result = names.stream()
					<!-- 리스트를 스트림으로 바꿈 -->
        .filter(name -> name.length() >= 4)
    	<!-- 길이가 4 이상인 것만 남김 -->
        .map(name -> name.toUpperCase())
		<!-- 남은 값을 대문자로 바꿈 -->
        .collect(Collectors.toList());
		<!-- 다시 List로 모음 -->

-> 결과 : ["PARK", "KANG"]

stream() : 데이터 흐름 만들기
filter() : 조건에 맞는 것만 남기기
map() : 값을 다른 형태로 바꾸기
sorted() : 정렬하기
collect() : 결과를 컬렉션으로 모으기
forEach() : 하나씩 꺼내서 실행하기

profile
잔디 속 새싹 하나

0개의 댓글