java의 Stream에 대해 설명한다

자바에서
각 개체들 간의 중간 매개자!
스트림이란 데이터의 이상화된 흐름을 의미한다!
즉, 스트림은 운영체제에 의해 생성되는 가상의 연결 고리를 의미하며
중간 매개자 역할을 한다!
parallelStream() 메소드를 통한 손쉬운 병렬 처리를 지원합니다.그렇다면 스트림 API의 동작 흐름은?
Stream<String> strStream1 = strList.stream();
Stream<String> strStream2 = Arrays.stream(strArr);
스트림을 생성한다고 해도 clone과 같이 스트림은 데이터 소스를 변경하지 않는다.
스트림은 일회용이다.
스트림은 작업을 내부 반복으로 처리한다.(작업이 간결할 수 있는 비결중의 하나)
반복문을 내부에 숨길수 있다는것이다.
stream.forEach(System.out::println); // 메서드 참조
stream.forEach(System.out.println(str)); // 람다식
스트림의 중간 연산 목록
- 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) 스트림의 요소를 수집한다. 주로 요소를 그룹화 하거나 분할한 결과를 컬렉션에 담에 반환하는데 사용한다.
함수형 인터페이스란 1 개의 추상 메소드를 갖는 인터페이스를 말다.
Java8 부터 인터페이스는
기본 구현체를 포함한 디폴트 메서드 (default method) 를 포함할 수 있다.
자바의 람다 표현식은 함수형 인터페이스로만 사용 가능하다.
=> Stream에서 사용되는 람다 식들은 모두 함수형 인터페이스를 구현한 구현체 객체란 소리!!!
추상 메서드가 한개 이기 때문에 람다식을 함수형 인터페이스에 넣는다면 자동으로 추상메서드가 람다식이 되어버린다!
Function<String, Integer> fuc = s ->Integer.parseInt(s);
람다식은 메서드 참조로 더욱 간단하게 표현할수있다!!
// 어짜피 s는 String이 확실하고 메서드에 인자로 들어가야 하므로
Function<String, Integer> fuc = Integer::parseInt;
또한 생성자 같은 경우는 new 키워드를 메서드처럼 명시하여 작성 할 수있다.
// String클래스에는 String(String original) 생성자가 정의되어있기 때문에 가능하다!
Function<String, String> fuc = String::new;
// 또한 Stream을 배열로 바꿀때 사용되곤 한다.
String[] array = Arrays.stream(strs).toArray(String[]::new);
| 함수형 인터페이스 | Descripter | Method | 번역 |
|---|---|---|---|
| Predicate | T -> boolean | boolean test(T t) | 서술어 |
| Consumer | T -> void | void accept(T t) | 소비자 |
| Supplier | () -> T | T get() | 공급자 |
| Function<T, R> | T -> R | R apply(T t) | 함수 |
| Comparator | (T, T) -> int | int compare(T o1, T o2) | 비교기 |
| Runnable | () -> void | void run() | 실행가능한 |
| Callable | () -> T | V call() | 호출가능한 |
map

filter

sorted

Comparator를 쉽게 만들어주는 Comparator.comparing static 메서드가 존재한다.
foreach

strean 객체를 정렬할때 sorted메서드를 사용한다.
하지만 내가 원하는 것은 최신 날짜, 최신 Id 순으로 정렬하고 싶었다.
list.stream()
.sorted(
Comparator.comparing(ReviewDAO::getDateTime).reversed()
.thenComparing(Comparator.comparing(ReviewDAO::getReviewId).reversed())
).limit(10)
하지만 이렇게 하면 reverse가 두번 먹어 늦은 날짜, 최신 ID순으로 정렬 된다.
따라서
Comparator<ReviewDAO> reversed = Comparator.comparing(ReviewDAO::getReviewId).reversed();
List<ReviewDAO> recent = list.stream()
.filter(reviewDAO -> reviewDAO.getGameId() == gameId)
.sorted(
Comparator.comparing(ReviewDAO::getDateTime).reversed()
.thenComparing(reversed)
)
.limit(10)
.collect(Collectors.toList());
위처럼 Comparator를 미리 구현하여 중복 reverse를 막는다.