2016-07-03 1 views
2

Java 8 스트림을 사용하는 방법을 배우고 있습니다. 이 코드 조각을 디버깅하는 동안 :Java8 수집기에서 제어 흐름은 어떻게됩니까?

Collector<Person, StringJoiner, String> collector = 
    Collector.of(
     () -> new StringJoiner(" | "), 
     (j,p) -> j.add(p.name.toLowerCase()), 
     StringJoiner::merge, 
     StringJoiner::toString); 
     System.out.println(persons.stream().collect(collector)); 

실행은 결코 StringJoiner::merge 또는 StringJoiner::toString에 도달하지 않습니다. 결합 자 (StringJoiner::merge)를 null로 바꾸면 코드에서 널 포인터 예외가 발생합니다. 나는 따라갈 수 없다.

추가 (관련) 질문 : 나는 람다 디버깅에 대한 로깅을 추가 할 수있는 방법

? 여러 줄 코드 블록에 중괄호를 추가하려고 시도했습니다.

Collector<Person, StringJoiner, String> collector = 
    Collector.of(
     () -> { 
     System.out.println("Supplier"); 
     new StringJoiner(" | ")}, 
     (j,p) -> j.add(p.name.toLowerCase()), 
     StringJoiner::merge, 
     StringJoiner::toString); 
+0

에 병합 소목 변환

  • 의해 서로 병합하는 방법 참조는 함수 객체 직접 효율 이점 O 인 대상 메소드를 호출 작성 f 메소드 참조. 그러나 이는 소스 코드에 연결되지 않아 코드 흐름을 가로 챌 수 있음을 의미합니다. 그런데 람다 식을 블록 형식으로 변환하여 중단 점을 설치할 필요가 없습니다. * 줄 디버깅 * 작업을하기 위해 적절한 줄 바꿈을 삽입하는 것입니다. – Holger

  • 답변

    3

    다음은 디버그 추가 문 (내가 문자열로 사람을 대체하지만, 아무것도 변경되지 않음)에 코드입니다 : 이것은 컴파일되지 않습니다

    List<String> persons = Arrays.asList("John", "Mary", "Jack", "Jen"); 
        Collector<String, StringJoiner, String> collector = 
         Collector.of(
          () -> { 
           System.out.println("Supplier"); 
           return new StringJoiner(" | "); 
          }, 
          (j, p) -> { 
           System.out.println("Accumulator"); 
           j.add(p.toLowerCase()); 
          }, 
          (stringJoiner, other) -> { 
           System.out.println("Combiner"); 
           return stringJoiner.merge(other); 
          }, 
          (stringJoiner) -> { 
           System.out.println("Finisher"); 
           return stringJoiner.toString(); 
          }); 
        System.out.println(persons.stream().collect(collector)); 
    

    실행을, 당신은 볼 수 있습니다 마무리는 확실히 불려 가도록 :

    • StringJoiner는
    • 은 모든 사람이 목공에 추가 된 공급 업체에 의해 만들어진
    • 널를 확인하는 방법 of() 의해 요구되지만
    • 피니셔은 문자열

    결합기에 소목 변환하지만, 콜렉터가 병렬 스트림을 사용하는 경우에만 적용하고, 스트림 정말로 다중 스레드에서 작업을 분할하여 다중 결합자를 사용하고 결합하는 것을 결정합니다. 사용되는 스레드의 수는 스트림에 의해 결정

    List<String> persons = new ArrayList<>(); 
        for (int i = 0; i < 1_000_000; i++) { 
         persons.add("p_" + i); 
        } 
        Collector<String, StringJoiner, String> collector = 
         Collector.of(
          () -> { 
           System.out.println("Supplier"); 
           return new StringJoiner(" | "); 
          }, 
          (j, p) -> { 
           System.out.println("Accumulator"); 
           j.add(p.toLowerCase()); 
          }, 
          (stringJoiner, other) -> { 
           System.out.println("Combiner"); 
           return stringJoiner.merge(other); 
          }, 
          (stringJoiner) -> { 
           System.out.println("Finisher"); 
           return stringJoiner.toString(); 
          }); 
        System.out.println(persons.parallelStream().collect(collector)); 
    

    :

    은을 테스트하려면 컬렉션에있는 사람들의 높은 숫자, 대신 순차적 하나의 병렬 스트림을해야합니다. 그리고 그것은 좋은 생각이라고 생각하면 한 스레드가 수행 한 작업을 중간의 다른 두 스레드로 나눌 수 있습니다. 그냥 그것을 사용하도록 선택 가정하자 2 :

    • 이 StringJoiners는 공급 업체가 생성되며, 스레드는
    • 각 스레드는 목공에 사람의 절반을 추가 각 목공에 할당되는
    • 두 합류 한 결합기 피니셔은 문자열 대부분의 경우