2017-06-02 110 views
1

我想知道是否有可能使用流來調用列表中的每個元素上的函數,並且還可以使用流調用其值以及其值。如何在JAVA的列表中的每個元素上運行一個函數?

比方說,我有一個整數列表: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)的列表。

+1

使用'map'代替 – Li357

+1

變異你通過流遍歷集合似乎是一個非常糟糕的主意開始。您可能更適合用更新的值生成新的「List」。 – Mena

+3

流的許多優點之一是它不鼓勵變異的數據結構。 – slim

回答

2

您需要使用map單獨collectstream不修改現有的列表,如:

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); 
+0

非常感謝Darshan Mehta! – Engineer

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(見Darshan的回答的第二部分爲一個簡單的例子)
+0

非常感謝你!我想問一下'i [0] ++'部分,我從來沒有見過像這樣的索引的使用,你知道我在哪裏可以找到有關這種方式的信息,以及爲什麼正常的int不起作用? – Engineer

+0

@Engineer不用客氣。基於數組的索引(而不是簡單的'int')發生的事情是,在lambda內部,方法的局部範圍內的變量(等等)必須被有效地「最終」引用。但是,顯然不能重新指定多個「final int」。但是你可以改變一個int []'。或者一個'AtomicInteger'。 – Mena

+0

@Engineer注意到上述內容更接近「客廳技巧」,而不是一般慣例,我向您展示的解決方案的另一面紅旗 - 從不在生產中使用! – Mena

1

雖然有辦法新List隨時修改輸入列表,我們已經學會了避免這樣做,因爲它會導致問題。

您可以用新的列表替換現有列表(在當前範圍),很容易地:

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

這是非常乾淨的。您的舊名單仍然存在(直到潛在的垃圾收集)。任何其他引用它都沒有改變 - 這是健康的。如果沒有更多的引用,它是垃圾收集。

+0

非常感謝你苗條!所以你說Streams是爲了_not_不得不修改原始對象的值而創建的? – Engineer

+0

好吧,你永遠不會*修改原始對象的值。但是流是鼓勵你不用的代碼。 – slim

2

不需要流。你可以只用List.replaceAll

list.replaceAll(MyApplication::plusOne); 
相關問題