[스터디]Java의 정석 27일차

Kristopher·2022년 1월 31일
0

Java 스터디

목록 보기
27/31

(CH14) 2. 스트림 ~ 2.5 스트림의 최종 연산

스트림이란?

반복된 연산이나 중복된 기능의 메서드들에 대한 문제를 해결하기 위해 만든 것이 스트림이다. 스트림은 데이터 소스를 추상화하고, 데이터를 다루는데 자주 사용되는 메서드들을 정의해 놓았다. 데이터 소스를 추상화하여 데이터 소스가 무엇이건 같은 방식으로 다룰 수 있어 코드의 재사용성을 높일 수 있다. 다음은 스트림에 대한 몇가지 특징들이다.

  • 스트림은 데이터 소스를 변경하지 않는다. 필요한 경우 정렬된 결과를 컬렉션이나 배열로 반환.
  • 스트림은 Iterator처럼 일회용이기 때문에 최종 연산이 수행되면 다시 사용할 수 없다.
  • 스트림은 내부 반복으로 작업을 처리하여 데이터 소스의 모든 요소에 적용한다.
  • 스트림에는 중간 연산과 최종 연산이 있는데, 중간 연산은 연산 결과를 스트림으로 반환하여 연속해서 연결할 수 있고, 최종 연산은 스트림의 요소를 소모하기 때문에 한번만 가능하다.
  • 최종 연산이 수행되기 전까지 중간 연산은 지연된다.
  • 스트림으로 데이터 처리시 fork&join 프레임워크를 자동 호출하여 연산을 병렬로 수행한다.

스트림 생성하기

스트림의 소스가 될 수 있는 대상은 배열, 컬렉션, 임의의 수 등 다양하다. stream()을 사용하여 각 대상을 소스로 하는 스트림을 반환한다.

컬렌션

Stream<T> Collections.stream()

컬렌션들의 최고 조상인 Collection에 stream()이 정의되어 있어 Collection의 자손인 List, Set을 구현한 컬렉션 클래스들은 모두 이 메서드로 스트림을 반환할 수 있다.

배열

Stream<T> Stream.of(T... values)
Stream<T> Stream.of(T[])
Stream<T> Arrays.stream(T[])
Stream<T> Arrays.stream(T[] array, int startInclusive, int endExclusive)

배열을 소스로 하는 스트림은 Stream과 Arrays에 static 메서드로 정의되어 있다.

특정 범위의 정수

오토박싱&언박싱으로 인한 비효율을 줄이기 위해 데이터 소스의 요소를 기본형으로 다루는 IntStream, LongStream, DoubleStream이 제공된다.

IntStream.range(int begin, int end) // end가 범위에 미포함
IntStream.rangeClosed(int begin, int end) // end가 범위에 포함

임의의 수

난수를 생성하는데 사용하는 Random클래스에 크기가 정해지지 않은 무한 스트림을 반환하는 메러드들이 포함되어 있다.

IntStream ints()
LongStream longs()
DoubleStream doubles()

무한 스트림의 경우 limit()를 활용하여 스트림의 크기를 제한해 주어야 한다. 위의 메서드들에 매개변수를 넣어 스트림의 크기를 지정하거나 일정 범위내에 있는 수만 생성시키는 방법도 존재한다.

람다식 - iterate(), generate()

Stream클래스의 iterate()와 generate()는 람다식을 매개변수로 받아서, 이 람다식에 의해 계산되는 값들을 요소로 하는 무한 스트림을 생성한다.

static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
static <T> Stream<T> generate(Supplier<T> s)

파일

지정된 디렉토리에 있는 파일의 목록을 소스로 하는 스트림을 생성하여 반환할 수도 있다.

Stream<Path> Files.list(Path dir)

두 스트림의 연결

Stream의 static메서드인 concat()을 사용하면 두 스트림을 하나로 연결할 수 있다. 이 때 연결하려는 두 스트림의 요소는 같은 타입이어야 한다.

스트림의 중간 연산

skip(), limit() : 스트림의 일부를 잘라낼 때 사용
filter(), distinct() : 스트림의 요소를 걸러낼 때 사용
sorted() : 스트림을 정렬할 때 사용
map() : 스트림의 요소에 저장된 값 중에서 원하는 필드로 뽑아내거나 특정 형태로 변환할 때 사용(연산의 결과로 Stream< T >타입의 스트림 반환)
peek() : 연산의 결과가 올바르게 처리되었는지 확인할 때 사용(중복 사용가능)
mapToInt(), mapToLong(), mapToDouble() : 스트림의 요소를 기본형으로 변환
flatMap() : Stream<T[]>를 Stream< T > 로 변환

Optional< T >와 OptionalInt

Optional< T >는 지네릭 클래스로 T타입의 객체를 감싸는 래퍼 클래스이다. 최종 연산 결과를 그냥 반환하는 것이 아니라 Optional객체에 담아 반환하면 Optional에 정의된 메서드로 반환 결과를 쉽게 확인할 수 있다.

Stream과 마찬가지로 Optional에도 기본형을 값으로 갖는 OptionalInt, OptionalLong, OptionalDouble이 존재한다. OptionalInt에 정의된 메서드들은 다음과 같다.

OptionalInt findAny()
OptionalInt findFirst()
OptionalInt reduce(IntBinaryOperator op)
OptionalInt max()
OptionalInt min()
OptionalInt average()

스트림의 최종 연산

forEach() : 스트림의 요소를 소모하여 출력하는 용도로 사용
allMatch(), anyMatch(), noneMatch(), findFirst(), findAny() : 조건에 맞는지 확인
count(), sum(), average(), max(), min() : 통계값 반환
reduce() : 스트림의 요소를 줄여나가면서 연산을 수행하고 최종결과 반환

Reference

Java의 정석
남궁성의 정석코딩

profile
개발자 지망생입니다.

0개의 댓글