有状态和无状态lambda表达式之间有什么区别?

Mau*_*ice 7 java parallel-processing lambda java-stream

根据OCP的书,人们必须避免有状态的操作,否则称为有状态的lambda表达.本书中提供的定义是"有状态的lambda表达式,其结果取决于在执行管道期间可能发生变化的任何状态."

它们提供了一个示例,其中使用并行流将固定的数字集合添加到使用该.map()函数的同步ArrayList中.

arraylist中的顺序是完全随机的,这应该让人看到有状态的lambda表达式在运行时产生不可预测的结果.这就是为什么强烈建议在使用并行流时避免有状态操作以消除任何潜在的数据副作用.

它们没有显示无状态lambda表达式,它提供了解决同一问题的方法(向同步的arraylist添加数字),我仍然不知道使用map函数用数据填充空的同步arraylist的问题. ..在执行管道期间可能发生变化的状态究竟是什么?他们指的是Arraylist本身吗?就像当另一个线程决定在并行流仍处于添加数字并因此改变最终结果的过程中时将其他数据添加到ArrayList时?

也许有人可以为我提供一个更好的例子来说明有状态的lambda表达式是什么以及为什么要避免它.非常感谢.

谢谢

Eug*_*ene 5

第一个问题是这样的:

 List<Integer> list = new ArrayList<>();

    List<Integer> result = Stream.of(1, 2, 3, 4, 5, 6)
            .parallel()
            .map(x -> {
                list.add(x);
                return x;
            })
            .collect(Collectors.toList());

System.out.println(list);
Run Code Online (Sandbox Code Playgroud)

您不知道这里的结果是什么,因为您正在向非线程安全集合添加元素ArrayList

但即使你这样做:

  List<Integer> list = Collections.synchronizedList(new ArrayList<>());
Run Code Online (Sandbox Code Playgroud)

并执行相同的操作,但list没有可预测的顺序。多个线程添加到此同步集合中。通过添加同步集合,您可以保证添加所有元素(与普通元素相反ArrayList),但它们的出现顺序未知

请注意,list没有顺序保证,这称为处理顺序。对于这个特定的例子来说,Whileresult 保证是:[1, 2, 3, 4, 5, 6]

根据问题的不同,您通常可以取消这些stateful操作;对于您的示例,返回synchronized List将是:

 Stream.of(1, 2, 3, 4, 5, 6)
            .filter(x -> x > 2) // for example a filter is present
            .collect(Collectors.collectingAndThen(Collectors.toList(), 
                          Collections::synchronizedList));
Run Code Online (Sandbox Code Playgroud)


Jer*_*and 3

为了尝试举一个例子,让我们考虑以下内容Consumer(注意:这样的函数的有用性不是这里的问题):

public static class StatefulConsumer implements IntConsumer {

    private static final Integer ARBITRARY_THRESHOLD = 10;
    private boolean flag = false;
    private final List<Integer> list = new ArrayList<>();

    @Override
    public void accept(int value) {
        if(flag){   // exit condition
            return; 
        }
        if(value >= ARBITRARY_THRESHOLD){
            flag = true;
        }
        list.add(value); 
    }

}
Run Code Online (Sandbox Code Playgroud)

它是一个将向 a 添加项目的消费者List(我们不考虑如何取回列表或线程安全性)并具有一个标志(表示有状态)。

这背后的逻辑是,一旦达到阈值,消费者就应该停止添加商品。

你的书试图说的是,因为没有保证函数必须消耗 的元素的顺序Stream,所以输出是不确定的。

因此,他们建议您仅使用无状态函数,这意味着它们始终会使用相同的输入产生相同的结果。