자바에서는 파일이나 콘솔의 입출력을 직접 다루지 않고, 스트림(stream)이라는 흐름을 통해 다룹니다. 스트림이란 실제의 입력이나 출력이 표현된 데이터의 이상화된 흐름을 의미합니다. 즉, 스트림은 운영체제에 의해 생성되는 가상의 연결 고리를 의미하며, 중간 매개자 역활을 합니다.
우리는 이 123의 순서를 한줄에 작성할 수 있음을 알 수 있습니다. 하지만 지연된연산을 통하여 최초 스트림 생성부터 중개연산을 거듭하여 최종연산까지의 과정을 지연됨을 알고 있습니다.
스트림을 어떻게 생성하고, 어떻게 중간연산하며, 어떻게 최종연산 하는지 알아봐요.
Stream<String> strStream1 = strList.stream();
Stream<String> strStream2 = Arrays.stream(strArr);
이때 포인트는,
1. 스트림을 생성한다고 해도 clone과 같이 스트림은 데이터 소스를 변경하지 않는다.
2. 스트림은 일회용이다.
3. 스트림은 작업을 내부 반복으로 처리한다.(작업이 간결할 수 있는 비결중의 하나)
내부 반복이란?
반복문을 메서드 내부에 숨길 수 있다는 것을 의미힌다.
for(String str : strList)
System.out.println(str);
↓
↓
↓
stream.forEach(System.out::println); // 메서드 참조
stream.forEach(System.out.println(str)); // 람다식
String[] strArr = { "dd", "aaa", "CC", "cc", "b" }; // 최초 문자열 데이터
// of()를 사용하여 stream객체에 값 입력
Stream<String> stream = Stream.of(strArr); // 문자열 배열이 소스인 스트림 생성
// filter()를 사용하여 조건에 맞지 않는 요소 제외
Stream<String> filteredStream = stream.filter(); // 걸러내기(중간 연산)
// distinct()를 사용하여 중복제거
Stream<String> distinctedStream = stream.distinct(); // 중복제거(중간 연산)
// 직접 코드를 쳐봤는데 sort()가 없음.. 자바의 정석 오타인가?
sorted()를 이용한 정렬
Stream<String> sortedStream = stream.sorted(); // 정렬(중간 연산)
Stream<String> limitedStream = stream.limit(5); // 스트림 자르기(중간 연산)
int total = stream.count(); // 요소 개수 세기(최종 연산)
스트림의 중간 연산 목록
- Stream<T> distinct() 중복을 제거 - Stream<T> filter(Predicate<T> predicate) 조건에 안 맞는 요소 제외 - Stream<T> limit(long maxSize) 스트림의 일부를 잘라냄 - Stream<T> skip(long n) 스트림의 일부를 건너뜀 - Stream<T> peek(Consumer<T> action) 스트림의 요소에 작업수행 - Stream<T> sorted() 스트림의 요소를 정렬 Stream<T> sorted(Comparator<T> comparator) - Stream<R> map(Function<T,R> mapper) 스트림의 요소를 변환 DoubleStream mapToDouble(ToDoubleFunction<T> mapper) IntStream mapToInt(ToIntFunction<T> mapper) LongStream mapToLong(ToLongFunction<T> mapper) Stream<R> flatmap(Function<T,Stream<R>> mapper) DoubleStream flatMapToDouble(Function<T,DoubleStream> m) IntStream flatMapToInt(Function<T,IntStream> m) LongStream flatMapToLong(Function<T,LongStream> m)
스트림의 최종 연산 목록
- 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<> p) // 모두 만족하지 않는지 - Object[] toArray() A[] toArray(IntFunction<A[]> generator) 스트림의 모든 요소를 배열로 반환 - Optinal<T> reduce(BinaryOperator<T> accumulator) 스트림의 요소를 하나씩 줄여가면서(리듀싱) 계산 T reduce(T identity, BinaryOperator<T> accumulator) U reduce(U identity, BiFunction<U,T,U> accumulator,BinaryOperator<U> combiner) - R collect(Collector<T,A,R> collector) 스트림의 요소를 수집한다. 주로 요소를 그룹화 하거나 분할한 결과를 컬렉션에 담에 반환하는데 사용한다.
중간 연산은 map(), flatMap() / 최종 연산은 reduce(), collect()가 핵심
혹시 오토박싱과 언박싱이 무엇인지 기억나시나요?
자바에는 기본타입과 Wrapper클래스가 존재합니다.
// 박싱
int i = 10;
Integer num = new Integer(i);
// 언박싱
Integer num = new Integer(10);
int i = num.intValue();
Stream<T> Collection.stream()
IntStream IntStream.range(int begin, int end)
IntStream IntStream.rangeClosed(int begin, int end)
// 이 메서드들은 크기가 정해지지 않은 무한스트림을 반환한다.
// 그러므로 limit()를 같이 사용하여 스트림의 크기를 제한해주는게 좋다.
// 하지만 아래와 같이 가인수가 있으면 제한해주지 않아도 된다.
IntStream ints(long streamSize)
LongStream longs(long streamSize)
DoubleStream doubles(long streamSize)
작성중입니다.
쉽게 설명해주셔서 많은 참고가 됐습니다. 이후 람다식 내용이 궁금합니다.