简体   繁体   中英

How to run a function on each element in a list in JAVA?

I would like to know if it's possible to use streams to call a function on each element in a list and to modify its value as well.

Let's say I have a list of integers: List<Integer> list = Arrays.asList(1,2,3);

And a method that increments every number by one:

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

This is what I used to call the function on each element and modify the original list:

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

However, I wanted to know if there is a shorter way of writing this using streams?

I tried using:

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

But it doesn't seem to change the original list, nor return anything... If it's impossible to change the original list using streams, how can I at least get a new modified copy of the list?

The output, by the way, should be a list of (2,3,4) after calling the function on the list.

No need for a Stream. You can just use List.replaceAll :

list.replaceAll(MyApplication::plusOne);

You need to use map with collect as stream alone does not modify the existing list, eg:

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);
}

Or even,

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

You can mutate your List while streaming it through the following idiom.

Note that this is absolutely horrible code , and constitutes a horrible practice altogether.

Only for experimenting.

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

Output

[2, 3, 4]

Notes

  • This will work with the above idiom because there is no parallel processing of the stream, and the indexing array container is mutated predictably.
  • The recommended practice is to generate a new List by streaming, mapping the values to their increment and collecting as List (see second part of Darshan 's answer for a trivial example)

Although there are ways to modify the input list as you go, we have learned to avoid doing so, because it causes problems.

You can replace the existing list (in the current scope) with the new list, pretty easily:

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

This is nice and clean. Your old list still exists (until potential garbage-collection). Any other references to it see no change -- which is healthy. If there are no more references to it, it's garbage-collected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM