Поток и ленивая оценка

Я читаю из java 8 API в абстракции потока, но Я не очень хорошо понимаю это предложение:

Промежуточные операции возвращают новый поток. Они всегда ленивы; выполнение промежуточной операции, такой как filter(), фактически не выполняется выполнить любую фильтрацию, но вместо этого создает новый поток, который, когда пройденный, содержит элементы исходного потока, которые соответствуют заданный предикат. Обход источника трубопровода не начинается до тех пор, пока выполняется операция терминала трубопровода.

Когда операция фильтра создает новый поток, этот поток содержит фильтрованный элемент? Похоже, что понятно, что поток содержит элементы только тогда, когда они пройдены с использованием терминальной операции. Но, чем, что содержит отфильтрованный поток? Я смущен!!!

Ответ 1

Это означает, что фильтр применяется только во время операции терминала. Подумайте о чем-то вроде этого:

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

(Это не компилирует и не упрощает реальность, но существует принцип)

Ответ 2

Потоки ленивы, поскольку промежуточные операции не оцениваются, если не задействована операция терминала.

Каждая промежуточная операция создает новый поток, сохраняет предоставленную операцию/функцию и возвращает новый поток.

Конвейер накапливает эти вновь созданные потоки.

Время, когда вызывается операция терминала, начинается обход потоков, и соответствующая функция выполняется один за другим.

Параллельные потоки не оценивают потоки "один за другим" (в конечной точке). Операции выполняются одновременно, в зависимости от доступных ядер.

Ответ 3

Мне кажется, что промежуточная операция не совсем ленива:

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

Задачи и результаты:

  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

Похоже, количество наборов итераций при создании потока, но получение нового элемента потока ленивым.