如何使用干扰方法和构造函数的流,以及为什么不使用.peek()?

时间:2017-06-25 21:26:09

标签: java java-8 java-stream

我将展示一个简化的问题示例来帮助演示它。

假设我正在尝试将旧的Java代码转换为java 8代码以实现样式和并行化(我这样做)。

这是代码:

    public static boolean deleteTester(List<Integer> keys) {
        DHeap dHeap = new DHeap(d, keys.size());
        DHeap_Item[] DHeap_ItemArray = keysListToDHeap_ItemArray(keys);
        dHeap.arrayToHeap(DHeap_ItemArray);

        for (int i = 0; i < keys.size(); i++) {
            keys.set(i, null);
            dHeap.delete(DHeap_ItemArray[i]);
            if (!someTest(keys, dHeap.getList()))
                return false;
        }
        return true;
    }

转化有几个问题:

  1. 我需要检查每次迭代,所以我无法减少/收集然后检查。
  2. 我正在访问一个数组和一个数据结构对象(测试人员正在使用),这意味着它不是非干扰的,并且不是无状态操作。
  3. 这是我尝试替换for循环:

        return IntStream.range(0, keys.size())
                //.parallel()
                .peek(idx -> keys.set(idx, null))
                .peek(idx -> dHeap.delete(DHeap_ItemArray[idx]))
                .allMatch(e -> someTest(keys, dHeap.getList()));
    

    更短且可读,但“违反了规则”,结果无法并行。

    所以我的问题是:

    1. 为什么我无法使用.parallal()? (我得到一个空指针ex。)
    2. 为什么我们不应该使用peek()?因为在这段代码中我没有别的办法看到它。
    3. 访问外部元素时应该怎么做?
    4. 我应该如何将代码“转移”到java 8流?
    5. 我缺少什么?
    6. 我猜答案是相互交织的。 我刚刚开始学习java 8,所以非常感谢所有的帮助,因为我真的被卡住了。

2 个答案:

答案 0 :(得分:2)

  

:为什么我无法使用.parallal()?

     

:访问外部元素时该怎么办?

你可以在并行流中使用它,当动作没有修改那里的共享状态时没有问题,例如:

curl "url"

如果操作修改共享状态,则它负责提供所需的同步,例如:

stream.peek(System.out::println).allMatch(...);
  

:为什么我们不应该使用peek()?

您可以使用stream.peek(it->{synchronized(lock){ keys.set(idx, null); }}).allMatch(...); 方法,但如果您无法控制流,则应避免使用peek(),例如:

peek()
  

:我该如何转移&#34; java 8流的代码?

详细说明了如何在包汇总java.util.stream中操作流。

答案 1 :(得分:1)

你绝对不应该像这样使用peek。 Streams API文档未指定元素仅在peek中的测试失败之前才会通过allMatch。流中的所有下注都是并行的,因为anyMatch不需要按顺序进行评估,即使另一个线程遇到违反{{1}的条件,也允许一个线程继续执行peek }。

即使流是连续的,anyMatch在某些情况下也可以执行意外的次数。请考虑以下代码:

peek

您可能认为它会打印最多3个数字,但事实上它会打印最多5个数字。