web-dev-qa-db-fra.com

Stream et évaluation paresseuse

Je lis de Java 8 API sur l'abstraction du flux mais je ne comprends pas très bien cette phrase:

Les opérations intermédiaires renvoient un nouveau flux. Ils sont toujours paresseux; l'exécution d'une opération intermédiaire telle que filter () n'effectue en fait aucun filtrage, mais crée à la place un nouveau flux qui, lorsqu'il est parcouru, contient les éléments du flux initial qui correspondent au prédicat donné. La traversée de la source du pipeline ne commence que lorsque l'opération terminale du pipeline est exécutée.

Lorsqu'une opération de filtrage crée un nouveau flux, ce flux contient-il un élément filtré? Il semble comprendre que le flux ne contient des éléments que lorsqu'il est traversé, c'est-à-dire avec une opération de terminal. Mais, que contient le flux filtré? Je suis confus!!!

33
xdevel2000

Cela signifie que le filtre n'est appliqué que pendant le fonctionnement du terminal. Pensez à quelque chose comme ça:

public Stream filter(Predicate p) {
    this.filter = p; // just store it, don't apply it yet
    return this; // in reality: return a new stream
}
public List collect() {
    for (Object o : stream) {
        if (filter.test(o)) list.add(o);
    }
    return list;
}

(Cela ne compile pas et c'est une simplification de la réalité mais le principe est là)

51
assylias

Les flux sont paresseux car les opérations intermédiaires ne sont évaluées que si l'opération de terminal est invoquée.

Chaque opération intermédiaire crée un nouveau flux, stocke l'opération/la fonction fournie et renvoie le nouveau flux.

Le pipeline accumule ces flux nouvellement créés.

Heure à laquelle l'opération du terminal est appelée, la traversée des flux commence et la fonction associée est exécutée une par une.

Les flux parallèles n'évaluent pas les flux "un par un" (au point terminal). Les opérations sont plutôt effectuées simultanément, selon les cœurs disponibles.

13
Nisarg Patil

Il me semble que cette opération intermédiaire n'est pas exactement paresseuse:

List<String> l3 = new ArrayList<String>();
        l3.add("first");
        l3.add("second");
        l3.add("third");
        l3.add("fouth");
        l3.add("fith");
        l3.add("sixth");

        List<String> test3 = new ArrayList<String>();
        try {
            l3.stream().filter(s -> { l3.clear(); test3.add(s); return true;}).forEach(System.out::println);
        } catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("!!! ");
            System.out.println(test3.stream().reduce((s1, s2) -> s1 += " ;" + s2).get());
        }

Otput:

  first
    null
    null
    null
    null
    null
    Java.util.ConcurrentModificationException
        at Java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.Java:1380)
        at Java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.Java:481)
        at Java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.Java:471)
        at Java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.Java:151)
        at Java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.Java:174)
        at Java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.Java:234)
        at Java.util.stream.ReferencePipeline.forEach(ReferencePipeline.Java:418)
        at test.TestParallel.main(TestParallel.Java:69)
    !!! 

    first ;null ;null ;null ;null ;null

On dirait le nombre de jeux d'itérations lors de la création de flux, mais en obtenant un nouvel élément de flux paresseux.

Comparer pour boucler avec compteur:

public static void main(String[] args) {
    List<Integer> list = new ArrayList<>(); 
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    list.add(5);
    int i = 0;
    while (i < list.size()) {
        System.out.println(list.get(i++));
        list.clear();
    }
}

Production:

1

Une seule itération attendue. J'accepte ce problème dans le comportement de lancement d'exception dans les flux, mais je pense que paresseux signifie obtenir des données (ou effectuer une action) uniquement lorsque je demande à un objet de le faire; et le nombre de données est également des données.