如何在JAVA列表中的每个元素上运行一个函数?

时间:2017-06-02 15:04:02

标签: java arrays list functional-programming java-stream

我想知道是否可以使用流来调用列表中每个元素的函数,以及 修改 它的值。

假设我有一个整数列表:List<Integer> list = Arrays.asList(1,2,3);

一种将每个数字递增一个的方法:

public static Integer plusOne(Integer n){
    return n + 1;
}

这是我以前在每个元素上调用函数并修改原始列表的原因:

for (int i = 0; i < list.size(); i++){
    list.set(i, plusOne(list.get(i)));
}

但是,我想知道是否有更短的方式使用流写这个?

我尝试使用:

list.stream()
    .forEach(e -> plusOne(e));

但它似乎没有更改原始列表,也没有返回任何内容......如果使用流更改原始列表是不可能的,我怎么能至少获得列表的新修改副本?

顺便说一句,在调用列表中的函数之后,输出应该是(2,3,4)的列表。

4 个答案:

答案 0 :(得分:3)

不需要Stream。您可以使用List.replaceAll

list.replaceAll(MyApplication::plusOne);

答案 1 :(得分:2)

您需要将mapcollect一起使用,因为stream不会修改现有列表,例如:

public static int plusOne(int i){
    return i + 1;
}

public static void main(String[] args) throws Exception{
    List<Integer> list = Arrays.asList(1,2,3);
    List<Integer> updated = list.stream()
            .map(i -> plusOne(i))
            .collect(Collectors.toList());
    System.out.println(updated);
}

甚至,

List<Integer> updated = list.stream()
            .map(i -> i + 1)
            .collect(Collectors.toList());
    System.out.println(updated);

答案 2 :(得分:1)

您可以通过以下习语对您的List进行变异播放。

请注意,这是绝对可怕的代码,并且完全构成了可怕的做法

仅用于试验。

List<Integer> list = Arrays.asList(1,2,3);
// cannot have a re-assignable index here as it requires being effectively final
int[] i = {0};
// iterating list
list.forEach(
    // for each element...
    (e) -> 
    // setting list at current index and incrementing index, with current value + 1
    list.set(i[0]++, e + 1)
);
System.out.println(list);

<强>输出

[2, 3, 4]

备注

  • 这将适用于上述习惯用法,因为没有流的并行处理,并且索引数组容器可预测地变异。
  • 建议的做法是通过流式处理生成新的List,将值映射到其增量并收集为List(请参阅Darshan的答案的第二部分一个简单的例子)

答案 3 :(得分:1)

虽然有很多方法可以随时修改输入列表,但我们已经学会避免这样做,因为它会导致问题。

您可以非常轻松地将现有列表(在当前范围内)替换为新列表:

 list = list.stream().map(...).collect(Collectors.toList());

这很干净。您的旧列表仍然存在(直到潜在的垃圾收集)。对它的任何其他引用都看不到任何变化 - 这是健康的。如果没有更多的引用,它就会被垃圾收集。