una streams recorrer lista for con colecciones coleccion java java-8 java-stream

streams - Modificar objetos dentro de la secuencia en Java8 mientras itera



stream java foreach (8)

En las transmisiones Java8, ¿puedo modificar / actualizar objetos dentro? Por ej. List<User> users :

users.stream().forEach(u -> u.setProperty("value"))


Como se mencionó anteriormente, no puede modificar la lista original, pero puede transmitir, modificar y recopilar elementos en una nueva lista. Aquí hay un ejemplo simple de cómo modificar el elemento de cadena.

public class StreamTest { @Test public void replaceInsideStream() { List<String> list = Arrays.asList("test1", "test2_attr", "test3"); List<String> output = list.stream().map(value -> value.replace("_attr", "")).collect(Collectors.toList()); System.out.println("Output: " + output); // Output: [test1, test2, test3] } }


En lugar de crear cosas extrañas, puede simplemente filter() y luego map() su resultado.

Esto es mucho más legible y seguro. Las transmisiones lo harán en un solo bucle.


Esto podría ser un poco tarde. Pero aquí está uno de los usos. Esto para obtener el recuento de la cantidad de archivos.

Cree un puntero a la memoria (un nuevo obj en este caso) y modifique la propiedad del objeto. La secuencia Java 8 no permite modificar el puntero en sí mismo y, por lo tanto, si declara contar solo como una variable e intenta aumentar dentro de la secuencia, nunca funcionará y arrojará una excepción del compilador en primer lugar

Path path = Paths.get("/Users/XXXX/static/test.txt"); Count c = new Count(); c.setCount(0); Files.lines(path).forEach(item -> { c.setCount(c.getCount()+1); System.out.println(item);}); System.out.println("line count,"+c); public static class Count{ private int count; public int getCount() { return count; } public void setCount(int count) { this.count = count; } @Override public String toString() { return "Count [count=" + count + "]"; } }


La forma funcional sería:

import static java.util.stream.Collectors.toList; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class PredicateTestRun { public static void main(String[] args) { List<String> lines = Arrays.asList("a", "b", "c"); System.out.println(lines); // [a, b, c] Predicate<? super String> predicate = value -> "b".equals(value); lines = lines.stream().filter(predicate.negate()).collect(toList()); System.out.println(lines); // [a, c] } }

En esta solución, la lista original no se modifica, pero debe contener el resultado esperado en una nueva lista a la que se puede acceder con la misma variable que la anterior.


Para deshacerse de ConcurrentModificationException, use CopyOnWriteArrayList


Para realizar modificaciones estructurales en la fuente de la secuencia, como mencionó Pshemo en su respuesta, una solución es crear una nueva instancia de una Collection como ArrayList con los elementos dentro de su lista primaria; iterar sobre la nueva lista y realizar las operaciones en la lista primaria.

new ArrayList<>(users).stream().forEach(u -> users.remove(u));


Puede utilizar removeIf para eliminar datos de una lista condicionalmente.

Por ejemplo: - Si desea eliminar todos los números pares de una lista, puede hacerlo de la siguiente manera.

final List<Integer> list = IntStream.range(1,100).boxed().collect(Collectors.toList()); list.removeIf(number -> number % 2 == 0);


Sí, puede modificar el estado de los objetos dentro de su transmisión, pero debe evitar modificar el estado de la fuente de transmisión. Desde la sección de non-interference de la documentación del paquete de flujo podemos leer que:

Para la mayoría de las fuentes de datos, prevenir la interferencia significa garantizar que la fuente de datos no se modifique en absoluto durante la ejecución de la canalización de flujo. La notable excepción a esto son las secuencias cuyas fuentes son colecciones concurrentes, que están específicamente diseñadas para manejar modificaciones concurrentes. Las fuentes de flujo concurrentes son aquellas cuyo Spliterator informa la característica CONCURRENT .

Entonces esto está bien

List<User> users = getUsers(); users.stream().forEach(u -> u.setProperty(value));

pero

users.stream().forEach(u -> users.remove(u));

no es y puede lanzar ConcurrentModificationException u otras excepciones como NPE:

List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); list.stream() .filter(i -> i > 5) .forEach(i -> list.remove(i)); //throws NullPointerException