0

我正在尝试获取元素列表,对这些元素的一部分进行一些操作,并将这些操作的输出放入一个新列表中。我只想在列表中进行一次迭代。

我发现这样做的唯一方法是:

List<Integer> newList = numList.stream().reduce(new ArrayList<Integer>(),
            (acc, value) -> {
                if (value % 2 == 0) {
                    acc.add(value * 10);
                }
                return acc;
            },
            (l1, l2) -> {
                l1.addAll(l2);
                return l1;
            }
        );

如您所见,这非常麻烦。

我当然可以使用filterthen map,但在这种情况下,我会迭代列表两次。

在其他语言(例如Javascript)中,这种reduce操作非常简单,例如:

arr.reduce((acc, value) => { 
    if (value % 2 == 0) {
        acc.push(value * 10);
    }
    return acc;
}, new Array())

惊人!我在想,Java 是否有更好的 reduce 版本,或者我编写的 Java 代码是执行这种操作的最短方法。

4

2 回答 2

7

我当然可以使用过滤器和它们映射,但在这种情况下,我会迭代列表两次。

这不是真的。的元素Stream被迭代一次,不管你有多少中间操作。

此外,执行可变归约的正确方法是使用collect

List<Integer> newList =
    numList.stream()
            .filter(v -> v % 2 == 0)
            .map(v -> v * 10)
            .collect(Collectors.toList());
于 2020-06-10T08:53:43.887 回答
2

您所做的与函数式编程相反,因为您使用函数只是为了获得副作用。

您可以简单地不使用 reduce 使其更加明确:

List<Integer> newList = numList.stream()
    .filter(value -> value % 2 == 0)
    .map(value -> value * 10)
    .collect(Collectors.toList());

编辑:Stream根据定义对集合进行一次迭代。根据javadoc

一个流应该只被操作一次(调用一个中间或终端流操作)。

于 2020-06-10T08:53:52.487 回答