waveofmymind
기록하는 습관
waveofmymind
전체 방문자
오늘
어제
  • 분류 전체보기 (124)
    • 📝 정리 (5)
    • 🌊TIL (9)
    • 💻CS (1)
      • 자료구조 (1)
    • 📙Language (9)
      • ☕Java (6)
      • 🤖Kotlin (3)
    • 🍃Spring (28)
    • 👨🏻‍💻알고리즘 (67)
      • 프로그래머스 (59)
      • 백준 (3)
    • 👷DevOps (4)
      • 🐳Docker (2)
      • 🤵Jenkins (1)

블로그 메뉴

  • 홈
  • Spring
  • Java
  • 알고리즘

공지사항

인기 글

태그

  • 챗GPT
  • 트랜잭션 전파
  • 다이나믹 프로그래밍
  • JDBC
  • CORS
  • 트랜잭션
  • 스프링 시큐리티
  • sql
  • 통합테스트
  • 스택
  • 스프링 부트
  • 코틀린
  • til
  • kotlin
  • chat GPT
  • BFS
  • resultset
  • LeetCode
  • 완전탐색
  • mybatis
  • 힙
  • Connection
  • 스프링
  • AOP
  • kotest
  • spring boot
  • Open AI
  • SpringAOP
  • spring
  • Spring Security

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
waveofmymind

기록하는 습관

[Java] 스트림(Stream) 잘 사용하기
📙Language/☕Java

[Java] 스트림(Stream) 잘 사용하기

2023. 3. 15. 16:00

스트림이란?

  • 스트림은 컬렉션이나 배열과 같은 데이터를 표준화된 방법으로 다루기 위한 것이다.
  • 데이터를 스트림으로 변환하여 여러번의 중간 연산을 하고, 최종 연산을 통해 다룰 수 있다.
  • 스트림의 동작 순서는 다음과 같다.
    1. 스트림 생성
    2. 중간 연산(반복 가능)
    3. 최종 연산
list.stream() // 스트림으로 만들고 -> 1번 과정
	.distinct() // 중복을 제거하고, -> 2번 과정
    .limit(2) // 일정 개수로 제한하고, -> 2번 과정
    .sorted() // 오름차순 정렬하고, -> 2번 과정
    .forEach(System.out::println) //각각의 값을 출력한다. -> 3번 과정

이 때 중간 연산의 경우 반복이 가능하다.

📚특징

  • 스트림은 일회성이다. 재사용이 필요하면 .stream()을 통해 다시 생성해줘야 한다.
  • 컬렉션이 아니다.
  • 최종 연산 전까지 중간 연산이 수행되지 않는다. 즉, 지연 연산이다.
  • 병렬 처리에 용이하다.
  • 기본형 스트림으로 IntStream, LongStream, DoubleStream 등이 있다.
    • Stream<Integer>와 같은 타입도 있지만, IntStream을 사용하면 .sum(), .average() 등과 같은 유용한 메서드를 제공한다.

스트림 사용하기


위에서 정리했듯이 스트림은 3가지 순서로 사용할 수 있는데,

  1. 스트림 생성
  2. 중간 연산
  3. 최종 연산

을 하나하나 정리해보자.

스트림 생성

  • Collection 의 경우 .stream()을 이용해서 손쉽게 스트림으로 변환할 수 있다.
Stream<Integer> stream = list.stream()
  • 객체 배열로부터 스트림을 생성하는 방법은 다음과 같다.
Stream.of("a", "b", "c");
Stream.of(new String[]{"a", "b", "c"});
Arrays.stream(new String[]{"a", "b", "c"});
Arrays.stream(new String[]{"a", "b", "c"}, startIndex, EndIndex+1);

중간 연산

  • 중간 연산으로 쓰이는 메서드는 다음과 같다.
.distinct() //중복 제거
.filter(Predicate<T> predicate) //조건에 안 맞는 요소는 제외
.limit(long maxSize) //maxSize 이후의 요소는 잘래냄
.skip(long n) //앞에서부터 n개 건너뛰기
.sorted() // 정렬기능, 디폴트는 오름차순
.sorted(Comparator<T> comparator) //조건에 맞게 요소 정렬. 추가 정렬 기준을 제공할 때는 thenComparing()사용
    
 //스트림의 요소를 변환할 때 사용하며, 람다식을 이용하여 활용할 수 있다. ex) map(File::getName), map(s->s.subString(3))
.map(Function<T> mapper) 
    
 //요소에 작업수행. 보통 중간 작업결과 확인으로 사용. peek(s->System.out.println(s))
.peek(Consumer<T> action)
    
 //스트림의 스트림을 스트림으로 변환
 //ex) Stream<String> strStrm=strArrStrm.flatMap(Arrays::stream)
.flatMap()

최종 연산

void forEach(Consumer<? super T> action) //각 요소에 지정된 작업 수행
void forEachOrdered(Consumer<? super T> action) //병렬 스트림의 경우 순서를 유지하며 수행
long count() //스트림의 요소 개수 반환

Optional<T> max(Comparator<? super T> comparator) //스트림의 최대값 반환
Optional<T> min(Comparator<? super T> comparator) //스트림의 최소값 반환

Optional<T> findAny() //아무거나 하나 반환. 벙렬 스트림에 사용
Optional<T> findFirst() //첫 번째 요소 반환. 순차 스트림에 사용

boolean allMatch(Predicate<T> p) //모든 조건을 만족?
boolean anyMatch(Predicate<T> p) //조건을 하나라도 만족?
boolean noneMatch(Predicate<T> p) //모든 조건을 만족하지 않음?

Object[] toArray() //모든 요소를 배열로 반환
A[] toArray(IntFunction<A[]> generator) //특정 타입의 배열로 반환

//스트림의 요소를 하나씩 줄여가면서 계산
//아래에서 자세히 보자
Optional<T> reduce(BinaryOperator<T> accumulator)

//데이터를 변형 등의 처리를 하고 원하는 자료형으로 변환해 준다.
collect( ~ )

활용

.map()

람다를 이용하여 새로운 스트림으로 변환 할 수 있다.

ex) Person 에서 getName() 메서드를 이용해 이름들의 새로운 스트림으로 만들기

ex) String 타입의 요소를 특정 문자열을 잘라서 새로운 스트림으로 만들기

list.stream().map(Person::getName)
list.stream().map(s -> s.subString(3))

.filter()

필터로 원하는 값만을 얻어올 수 있다.

람다식의 리턴값은 boolean이며, true일 경우에만 다음 단계로 진행된다.

list.stream()
		.filter(c -> c. getName().startWith("전"))
		.forEach(c -> System.out.println(c.getId));

.limit(2)

  • 개수를 제한하여 새로운 스트림을 생성한다.

. skip(2)

  • 앞에서 2개를 제외한 나머지를 스트림으로 생성한다.
Stream.iterate(10, i->i+1)
		.skip(10) //
        .limit(10)
        .forEach(System.out::println)

anyMatch(), allMatch(), nonMatch()

특정 문자열이 있는지 확인한다.

boolean result = Classes.stream()
				.anyMatch(b->b.getTitle().contains("k"));

findFirst(), findAny()

  • findFirst()는 stream에서 가장 앞에 있는 요소를 반환한다.
  • findAny()는 가장 먼저 찾은 요소를 반환한다. (맨 뒤에 있는 요소가 반환될 수도 있다.)

reduce()

  • 스트림의 요소를 하나씩 줄여가며 누적 연산을 수행한다.
  • reduce(초기값, (누적 변수, 요소) → 수행문)
Integer result = Stream.of(1,2,3,4,5,6,7,8,9,10)
										.reduce((total, y) -> total + y);
//초기값을 정할 경우
Integer result = Stream.of(1,2,3,4,5,6,7,8,9,10)
											 .reduce(10,(total,n) -> total +n);

collect()

  • 스트림의 요소를 자료형으로 바꿀 때 사용한다.
list.stream().collect(Collectors.toSet());
list.stream().collect(Collectors.toList()); 
list.stream().collect(Collectors.joining()); 
list.stream().collect(Collectors.joining(", "));

'📙Language > ☕Java' 카테고리의 다른 글

[Java] url 변수 동적으로 받도록 개선하기  (0) 2023.05.18
[트러블 슈팅] url 패턴이 같을 경우에 Controller 메서드 구별하기  (0) 2023.05.17
[JDBC] 동적으로 파라미터 바인딩 하기  (0) 2023.04.26
[JDBC] Connection과 PreparedStatement, 그리고 ResultSet  (0) 2023.04.24
[Java] Jackson Databind 이용하기  (0) 2023.03.02
    '📙Language/☕Java' 카테고리의 다른 글
    • [트러블 슈팅] url 패턴이 같을 경우에 Controller 메서드 구별하기
    • [JDBC] 동적으로 파라미터 바인딩 하기
    • [JDBC] Connection과 PreparedStatement, 그리고 ResultSet
    • [Java] Jackson Databind 이용하기
    waveofmymind
    waveofmymind

    티스토리툴바