자바 8 스 트림 배우 기

Stream 은 하나의 집합 에 대한 많은 조작 을 하나의 흐름 식 작업 으로 연결 시 키 고 유사 한 함수 식 프로 그래 밍 에 따라 코드 를 작성 하 며 인터페이스 가 시원하고 선명 하 다.  Stream 은 Guava 의 Fluent Iterable 시리즈 와 다르다.Fluent Iterable 시 리 즈 는 패키지 집합(List,Set 등)을 통 해 교체 기,get 을 다시 불 러 오 는 방식 으로 transform,filter 등 을 진행 하 며 간단 하고 성능 이 높다 는 장점 이 있 습 니 다.단점 은 기능 이 단일 하고 오용 하기 쉽다 는 것 이다.예 를 들 어 transform 이후 목록 의 모든 항목 은 본질 적 으로 하나의 보기(View)이지 실제 항목(값 대상)이 아 닙 니 다.get 방법 을 여러 번 호출 합 니 다.이 는 본질 적 으로 매번 Function 의 apply 방법 을 층 층 이 호출 하 는데 그 중에서 복잡 한 연산 이나 I/O 읽 기 가 있 으 면 효율 이 매우 낮다.*8195:8195:Stream 자체 가 일련의 데이터 구 조 를 구축 했다.그 중의 데 이 터 는 보기 만 이 아니 라 실제 존재 하 는 데이터 로 볼 수 있다.인터넷 에서 소스 코드 를 분석 하 는 글 이 매우 많 습 니 다.여 기 는 중복 설명 이 아니 라 이해 의 한 가지 사고 만 소개 합 니 다.첫째,몇 가지 관건 적 인 데이터 구조 이다.  Stream。인 터 페 이 스 는 BaseStream 으로 흐름 의 기본 적 인'형태'에 대한 설명 으로 볼 수 있다.혹은 모든 흐름 식 작업.뒤에 언급 된 파이프라인 도 베이스 스 트림 을 실 현 했 지만 더 쉽게 이해 할 수 있 을 것 같다.  Pipeline。공공 부 류 는 Abstract Pipeline 입 니 다.스 트림 작업 의 모든 숙제 라 고 볼 수 있 거나 모든 작업 노드 라 고 할 수 있다.불필요 한 포장 과 분해 작업 을 막 기 위해 레 퍼 런 스 피 플 린,인 트 피 플 린,롱 피 플 린,더 블 피 플 린 으로 나 뉘 었 다.이 파이프 들 은 세 가지 로 나 눌 수 있다.머리,종결 작업,비 종결 작업 이다.각각 대응 하 는 유형 은 XXXPipeline.Head,XXXPipeline.StatelessOp 과 XXXPipeline.StatefulOp,Terminal Op 이다.흐름 을 호출 하 는 작업 방법 은 모두 이런 Pipeline 을 만 들 수 있다.예 를 들 어 IntStream.of()를 호출 하면 머리 가 생 성 됩 니 다.Stream.map()를 호출 하면 비 종결 동작 이 생 성 됩 니 다.Stream.reduce()를 호출 하여 종료 동작 을 생 성 합 니 다.비 종결 작업 에서 opWrapSink 방법 을 실현 해 야 합 니 다.이 방법 은 Sink 로 돌아 가 야 합 니 다.  Sink。모든 조작 은 하나의 Sink 에 대응 합 니 다.각 싱 크,begin,end,accept 세 가지 방법 에 주목 합 니 다.현재 Sink 이 작 동 하지 않 으 면 downstream.accept 를 직접 호출 합 니 다.그렇지 않 으 면 현재 작업 결 과 를 매개 변수 로 downstream.accept 를 호출 합 니 다.다운 스 트림 은 어떤 콘 셉 트 인가요?예 를 들 어 하나의 흐름 은 IntStream.of(1,2,3).map(x->x+1).boxed().max()입 니 다.그러면 map 에 대응 하 는 sink 은 바로 머리의 downstream 이 고 boxed 에 대응 하 는 sink 은 map 의 downstream 입 니 다.종합 하면 머리의 accept 를 호출 하면 마지막 종료 작업 으로 층 층 이 호출 됩 니 다.종료 작업 은 opWrapSink 방법 이 없 기 때문에 후속 흐름 으로 호출 되 지 않 습 니 다.  Spliterator。스 트림 데이터 접근 도구.직렬 흐름 이 라면,안에 있 는 forEach Remaining 을 직접 호출 합 니 다.이 방법 은 action.accept 에 관심 을 가지 고 있 습 니 다.만약 에 모든 Sink 를 연결 했다 면 이 한 마디 호출 은 Sink 의 층 층 이 호출 되 기 시 작 했 습 니 다.이로써 기본 데이터 구 조 는 이런 것들 을 소개 한다.다음은 흐름 의 모든 노드 가 어떻게 연결 되 는 지 주목 합 니 다.『8195』모든 Stream 은 하나의 Pipeline 노드 로 구성 되 고 하나의 조작 을 추가 할 때마다 이 Pipeline 뒤에 Pipeline 구 조 를 추가 합 니 다.추가 적 으로 유지 되 는 정보 에 서 는 sourceStage(머리),previousStage(이전 Pipeline),sourceSupplier(스 트림 데이터 의 Spliterator),depth(Pipeline 길이)를 주목 합 니 다.마지막 작업 이 끝 날 때 까지 Pipeline 체인 을 연결 합 니 다.  종결 작업 은 reduce 든 collect 작업 이 든 모두 AbstracePipeline.evaluate 방법 으로 호출 됩 니 다.직렬 흐름 의 reduce 를 예 로 들 어 AbstractPipeline.wrapAndCopy Into 로 직접 호출 합 니 다.그 중에서 wrap 는 Pipeline 체인 을 옮 겨 다 니 며 각 단계 의 opWrapSink 을 호출 합 니 다.이렇게 모든 싱 크 는 메모리 데이터 의 포인터 링크 가 아 닌 방법 으로 한 층 씩 호출 되 며 첫 번 째 Pipeline 의 싱 크 링크 에서 끝까지 연 결 됩 니 다.
    @Override
    @SuppressWarnings("unchecked")
    final  Sink wrapSink(Sink sink) {
        Objects.requireNonNull(sink);

        for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
            sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
        }
        return (Sink) sink;
    }

  copy Into 는 Sink.begin,Spliterator.forEachRemaing,Sink.end 방법 을 순서대로 호출 합 니 다.앞에서 언급 한 바 와 같이 forEachRemaing 은 흐름 의 모든 데 이 터 를 매개 변수 로 하고 각 단계 의 Sink accept 를 층 층 이 호출 합 니 다.
    @Override
    final  void copyInto(Sink wrappedSink, Spliterator spliterator) {
        Objects.requireNonNull(wrappedSink);

        if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
            wrappedSink.begin(spliterator.getExactSizeIfKnown());
            spliterator.forEachRemaining(wrappedSink);
            wrappedSink.end();
        }
        else {
            copyIntoWithCancel(wrappedSink, spliterator);
        }
    }

이로써 전체 흐름 의 조작 은 위 에서 아래로 완전히 연결 되 었 다.

좋은 웹페이지 즐겨찾기