web-dev-qa-db-de.com

Objekte innerhalb des Streams in Java8 während des Durchlaufens ändern

Darf ich in Java8-Streams Objekte innerhalb von? .__ ändern oder aktualisieren? List<User> users:

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

Ja, Sie können den Status von Objekten innerhalb Ihres Streams ändern, Sie sollten jedoch den Status von source des Streams nicht ändern. Aus dem Abschnitt Nichtinterferenz der Streampaketdokumentation können wir Folgendes lesen:

Für die meisten Datenquellen bedeutet das Verhindern von Interferenzen, dass die Datenquelle während der Ausführung der Stream-Pipeline überhaupt nicht geändert wird. Die bemerkenswerte Ausnahme hiervon sind Streams, deren Quellen gleichzeitige Sammlungen sind, die speziell für gleichzeitige Änderungen ausgelegt sind. Gleichzeitige Stream-Quellen sind diejenigen, deren Spliterator die CONCURRENT-Eigenschaft angibt.

Das ist also in Ordnung

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

aber 

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

ist nicht und kann ConcurrentModificationException oder andere Ausnahmen wie NPE werfen:

List<Integer> list = IntStream.range(0, 10).boxed().collect(Collectors.toList());

list.stream()
    .filter(i -> i > 5)
    .forEach(i -> list.remove(i));  //throws NullPointerException
61
Pshemo

Um strukturelle Änderungen an der Quelle des Streams vorzunehmen, wie Pshemo in seiner Antwort erwähnt, besteht eine Lösung darin, eine neue Instanz einer Collection wie ArrayList mit den Elementen in Ihrer Primärliste zu erstellen. iterieren Sie über die neue Liste und führen Sie die Operationen in der Primärliste aus.

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

Der funktionale Weg wäre imho:

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]
    }
}

In dieser Lösung wird die ursprüngliche Liste nicht geändert, sondern sollte Ihr erwartetes Ergebnis in einer neuen Liste enthalten, auf die unter derselben Variablen wie der alten Liste zugegriffen werden kann

1

Befreien Sie sich von ConcurrentModificationException Use CopyOnWriteArrayList  

0
black-coder

Anstatt fremde Dinge zu erstellen, können Sie einfach filter() und dann map() Ihr Ergebnis.

Das ist viel lesbarer und sicherer. Streams machen es nur in einer Schleife.

0
Nicolas Zozol

Dies könnte etwas spät sein. Aber hier ist die Verwendung. Hiermit wird die Anzahl der Dateien ermittelt. 

Erstellen Sie einen Zeiger auf den Speicher (in diesem Fall ein neues Objekt) und ändern Sie die Eigenschaft des Objekts. Java 8-Stream erlaubt keine Änderung des Zeigers selbst. Wenn Sie also deklarieren, dass nur eine Variable zählt und versucht wird, den Stream zu erhöhen, wird er niemals funktionieren und überhaupt keine Compiler-Ausnahme auslösen

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 + "]";
        }



    }
0
Joey587

Sie können removeIf verwenden, um Daten aus einer Liste bedingt zu entfernen.

ZB: - Wenn Sie alle geraden Zahlen aus einer Liste entfernen möchten, können Sie dies wie folgt tun.

    final List<Integer> list = IntStream.range(1,100).boxed().collect(Collectors.toList());

    list.removeIf(number -> number % 2 == 0);
0
Jobin Joseph

Wie bereits erwähnt, können Sie die ursprüngliche Liste nicht ändern. Sie können jedoch Elemente streamen, ändern und in eine neue Liste aufnehmen. Hier ist ein einfaches Beispiel, wie Sie das String-Element ändern können.

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]
    }
}
0
Vadim