Java8收集器中的控制流如何?

时间:2016-07-03 04:14:49

标签: java-8 java-stream

我正在学习如何使用Java 8流。在调试这段代码时:

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::mergeStringJoiner::toString。如果我用null替换组合器(StringJoiner::merge),则代码抛出空指针异常。我无法跟进。

其他(相关)问题:

如何添加用于调试lambdas的日志记录?我尝试为多行代码块添加大括号。这不编译:

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

1 个答案:

答案 0 :(得分:3)

这里添加了调试语句的代码(我用字符串替换了Person,但它没有改变任何东西):

    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由供应商创建
  • 所有人都加入了木匠
  • 整理器将连接器转换为String

然而,组合器虽然需要检查null的方法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:

  • 供应商创建了两个StringJoiner,并为每个连接器分配了一个线程
  • 每个帖子将一半人加入其木匠
  • 两个加入者由组合器合并在一起
  • 整理器将合并的木匠变换为String