- 다양한 데이터 소스(컬렉션, 배열, 람다식, 난수 스트림 등)를 표준화된 방법으로 다루기 위한 것
- 스트림 만들기 -> 중간연산(0~n 번) -> 최종연산(1번)으로 결과를 얻음
1. 스트림의 특징
1) 데이터 소스로부터 데이터를 읽기만 할 뿐 변경하지 않음
- 필요시 정렬된 결과를 컬렉션이나 배열에 담아 반환 가능
2) Iterator처럼 일회용(필요한 경우 다시 스트림 생성해야 함)
3) 최종 연산 전까지 중간연산이 수행되지 않음 - 지연된 연산
IntStream intStream = new Random().ints(1, 46); // 1~ 45 범위의 무한 스트림
IntStream.distinct().limit(6).sorted() // 중간연산, 수행되지 않고 수행해야할 내용을 지정하는 것
.forEach(i -> System.out.print(i+",")); // 최종연산
4) 작업을 내부 반복으로 처리
// 반복문
for(String str : strList)
System,out,prinln(str);
// forEach()메서드는 스트림에 정의된 메서드로, 매개변수에 대입된 람다식을 데이터 소스의 모든 요소에 적용함
stream.forEach(System.out::prinln);
5) 작업을 병렬로 처리 - 병렬 스트림
- parallel() 메서드로 병렬 스트림으로 전환
6) 기본형 스트림 - IntStream, LongStream, DoubleStream
- 오토박싱&언박싱의 비효율이 제거됨(Stream <Integer> 대신 IntStream 사용)
- 숫자와 관련된 유효한 메서드를 Stream <T>보다 더 많이 제공
2. 스트림 만들기
1) 컬렉션을 스트림으로 만들기
- 컬렉션의 최고 조상인 Collection에 stream()이 정의되어 있음
- List와 Set으로 구현한 컬렉션은 stream() 메서드로 스트림 생성
// Collection 인터페이스의 stream()메서드를 이용하여 생성
Stream<E> stream()
2) 배열을 스트림으로 만들기
- Stream과 Arrays에 static 메서드로 정의되어 있음
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 endExlusive)
- 기본형 배열을 소스로 하는 스트림 생성 가능
3) 임의의 수(난수)를 갖는 스트림 생성
- Random클래스의 메서드 이용하여 임의의 수를 요소로 갖는 (무한) 스트림 생성
// 스트림의 크기가 정해지지 않은 무한 스트림(infinite stream) 반환하는 메서드
IntStream ints()
LongStream longs()
DoubleStream doubles()
- 스트림의 크기를 제한하여 유한 스트림 생성
// 매개변수로 스트림의 크기를 지정하여 유한 스트림(tream) 반환하는 메서드
IntStream ints(long streamSize)
LongStream longs(long streamSize)
DoubleStream doubles(long streamSize)
4) 특정 범위의 정수를 요소로 갖는 스트림 생성
IntStream IntStream.range(int begin, int end) // end 포함하지 않음
IntStream IntStream.rangeClosed(int begin, int end) // end 포함
5) 람다식을 이용한 스트림 생성
// 지정된 seed값을 시작으로 람다식 f에 의해 계산된 결과를 다시 seed값으로 하여 계산 반복하여 무한 스트림 생성(이전 요소에 종속적)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
// seed값 없이 람다식에 의해 계산되는 값을 요소로하는 무한 스트림 생성(이전 요소에 독립적)
static <T> Stream<T> generate(Supplier<T> s)
6) 파일을 소스로 하는 스트림 생성
- java.nio.file.Files는 파일을 다루는데 필요한 메서드 제공
// list()는 지정된 디렉토리(dir)에 있는 파일의 목록을 소스로하는 스트림을 생성하여 반환
Stream<Path> Files.list(Path dir) // Path는 파일 또는 디렉토리
// lines()는 파일의 한 라인을 요소로 하는 스트림을 생성하여 반환
Stream<String> Files.lines(Path path)
Stream<String> Files.lines(Path path, Charset cs)
// BufferedReader 클래스의 lines()메서드는 파일 뿐만 아니라 다른 입력 대상으로부터 데이터를 행단위로 읽어옴
Stream<String> lines()
7) 비어있는 스트림 생성
// empty()는 빈 스트림을 생성해서 반환
Stream emptyStream = Stream.empty();
3. 중간연산(0 ~ n 번)
- 연산결과가 스트림인 연산
- 반복적으로 적용 가능
1) 자르기 - skip(), limit()
// 앞에서부터 n개 건너뛰기
Stream<T> skip(long n)
// maxSize 이후의 요소 잘라내기
Stream<T> limit(long maxSize)
2) 요소 걸러내기 - filter(), distinct()
// 조건에 맞지 않는 요소 제거
Stream<T> filter(Predicate<? super T> predicate)
// 중복 제거
Stream<T> distinct()
3) 정렬 - sorted()
// 스트림 요소의 기본정렬(Comparable)로 정렬
Stream<T>
// 지정된 Comparator로 정렬
Stream<T> sorted(Comparator<? super T> comparator)
4) 정렬 - Comparator의 메서드 comparing(), thenComparing()
// comparing()메서드로 정렬기준 지정
comparing(Function<T, U> keyExtractor)
comparing(Function<T, U> keyExtractor, Comparator<U> keyComparator)
// 비교대상이 기본형인 경우
comparingInt(ToIntFuction<T> keyExtractor)
comparingLong(ToLongFunction<T> keyExtractor)
comparingDouble(ToDoubleFunction<T> keyExtractor)
// 정렬 조건 추가
thenComparing(Comparator<T> other)
thenComparing(Comparator<T, U> keyExtractor)
thenComparing(Comparator<T, U> keyExtractor, Comparator<U> keyComp)
5) 변환 - 원하는 필드만 뽑거나 특정 형태로 변환하는 map()
Stream<R> map(Function<? super T, ? extends R> mapper)
6) 스트림 요소를 소비하지 않고 엿보기(중간 작업 결과 확인) - peek()
// 중간 연산(스트림 요소를 소비하지 않음)
Stream<T> peek(Consumer<? super T> action)
7) 변환 - 스트림의 스트림을 스트림으로 변환하는 flatMap()
Stream<String> strStrStrm = strArrStrim.flatMap(Arrays::stream);
4. 최종연산(1번)
- 연산결과가 스트림이 아닌 연산
- 단 한 번만 적용 가능(스트림의 요소를 소모)
1) 스트림의 모든 요소에 지정된 작업 수행 - forEach(), forEachOrdered()
// 병렬 스트림인 경우 순서가 보장되지 않음
void forEach(Consumer<? super T> action)
// 병렬 스트림인 경우에도 순서가 보장됨
void forEachOrdered(Consumer<? super T> action)
// 직렬 스트림
IntStream.range(1, 10).sequential().forEach(System.out::print); // 순서가 보장됨
IntStream.range(1, 10).sequential().forEachOrdered(System.out::print); // 순서가 보장됨
// 병렬 스트림
IntStream.range(1, 10).parallel().forEach(System.out::print); // 순서가 보장되지 않음
IntStream.range(1, 10).parallel().forEachOrdered(System.out::print); // 순서가 보장됨
2) 조건 검사 - allMatch(), anyMatch(), noneMatch()
boolean allMatch(Predicate<? super T> predicate) // 모든 요소가 조건 만족시키면 true
boolean anyMatch(Predicate<? super T> predicate) // 한 요소라도 조건 만족시키면 true
boolean noneMatch(Predicate<? super T> predicate) // 모든 요소가 조건을 만족시키지 않으면 true
3) 조건에 일치하는 요소 찾기 - findFirst(), findAny()
Optional<T> findFirst() // 첫 번째 요소 반환, 순차 스트림에 사용
Optional<T> findAny() // 조건에 일치하는 요소 아무거나 하나 반환, 병렬 스트림에 사용
4) 스트림의 요소를 하나씩 줄여가며 누적연산 수행 - reduce()
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
U reduce(U identity, BiFunction<U,T,U> accumulator, BinaryOperator<T> combiner)
5) 스트림의 최종연산 - collect()
① collector() 최종연산
- Collector를 매개변수로 하는 스트림의 최종 연산
👉🏻 매개변수가 Collector를 구현한 클래스의 객체여야 함
Object colelct(Collector collector) // Collector를 구현한 클래스의 객체를 매개변수로 지정
Object collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)
② Collector 인터페이스
- collector()가 스트림의 요소를 수집하기 위한 방법(메서드)을 정의해 놓은 인터페이스
- 직접 구현해서 사용할 수 있지만 Collectors클래스에 다양한 기능을 구현되어 있어서 Collectors클래스만으로도 많은 일을 할 수 있음
③ Collectors 클래스
- Collector 인터페이스를 구현한 Collectors 클래스
- static 메서드로 미리 작성된 컬렉터 제공
분류 | 메서드 | 설명 |
스트림을 컬렉션으로 변환 | toList() | 스트림을 List로 변환 |
toSet() | 스트림을 Set으로 변환 | |
toMap() | 스트림을 Map으로 변환 | |
toCollection() | 스트림을 원하는 컬렉션의 생성자 참조를 매개변수로 넣어 원하는 컬렉션으로 변환 | |
스트림을 배열로 변환 | toArray() | 스트림을 배열로 변환 |
스트림의 통계 | counting() | 스트림 요소를 그룹별로 카운트(count()는 전체만 카운트 할 수 있음) |
summingInt() | 스트림 요소의 합계 반환(sum()은 전체를 더함) | |
maxBy() | 스트림 요소 중 최대값 반환 | |
minBy() | 스트림 요소 중 최소값 반환 | |
averageingInt() | 스트림 요소의 평균 값 반환 | |
스트림을 리듀싱 | reducing() | 스트림 그룹별 리듀싱(reduce()는 전체 리듀싱) |
스트림을 문자열로 결합 | joining() | 문자열 스트림의 요소를 모든 연결 |
스트림의 그룹화 | groupingBy() | 스트림의 요소를 특정 기준으로 그룹화(n분할) |
스트림의 분할 | partitioningBy() | - 스트림을 조건에 일치하는 것과 일치하지 않는 것으로 그룹화(2분할) - 이중 분할 가능 |
'Java' 카테고리의 다른 글
Java 입출력(I/O) (0) | 2023.01.26 |
---|---|
Java Optional<T> (0) | 2023.01.20 |
Java 람다(Lambda) (0) | 2023.01.17 |
Java 스레드(thread) (0) | 2023.01.17 |
Java 애너테이션(annotation)이란? (0) | 2023.01.17 |