Java 流与惰性评价

Java 流与惰性评价,java,java-8,java-stream,Java,Java 8,Java Stream,我在读《在线文摘》,但是 我不太明白这句话: 中间操作返回一个新的流。他们总是懒惰; 执行诸如filter()之类的中间操作实际上不会 执行任何筛选,但创建一个新流,当 遍历,包含与 给定谓词。管道源的遍历直到 执行管道的终端操作 当筛选操作创建新流时,该流是否包含筛选元素? 似乎可以理解,流只有在通过终端操作时才包含元素。但是,除此之外,什么包含过滤流?我很困惑 这意味着过滤器仅在终端操作期间应用。想想这样的事情: public Stream filter(Predicate p) {

我在读《在线文摘》,但是 我不太明白这句话:

中间操作返回一个新的流。他们总是懒惰; 执行诸如filter()之类的中间操作实际上不会 执行任何筛选,但创建一个新流,当 遍历,包含与 给定谓词。管道源的遍历直到 执行管道的终端操作

当筛选操作创建新流时,该流是否包含筛选元素?
似乎可以理解,流只有在通过终端操作时才包含元素。但是,除此之外,什么包含过滤流?我很困惑

这意味着过滤器仅在终端操作期间应用。想想这样的事情:

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

(这不是编译,是对现实的简化,但原理是存在的)

流是惰性的,因为除非调用终端操作,否则不会计算中间操作

每个中间操作创建一个新流,存储提供的操作/函数并返回新流

管道会累积这些新创建的流

调用终端操作时,开始遍历流并逐个执行相关功能


并行流不会“逐个”计算流(在终点)。这些操作是同时执行的,这取决于可用的内核。

在我看来,中间操作并不完全是懒惰的:

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());
        }
看起来像流创建时的迭代集数,但获取新的流元素是惰性的

与带计数器的循环进行比较:

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();
    }
}
只有一个预期的迭代。
我同意流中异常抛出行为的问题,但我认为懒惰意味着只有在我请求某个对象执行数据(或执行某些操作)时才获取数据;数据的计数也是数据

@Lukas,我们已经为Java8流API提供了一个。您创建的标记非常。。。但它的官方名称是“Streams API”,而不是“Java Stream”。Java流可以表示任何东西。包括InputStream/OutputStream等。无论如何,我想这应该被带到meta…你能不能通过突出显示并点击Ctrl+K来格式化你的代码,仅仅因为它迭代了6次并不意味着它不是懒惰的。查看
ArrayList
第1380行(forEachRemaining)的代码发生的情况是,它在遍历整个列表之前不会抛出ConcurrentModificationException。ForEachLeving是一个“终端操作”。“在遍历整个列表之前不会抛出ConcurrentModificationException。”我认为-只有在遍历“整个列表”(在list.clear()之后-整个列表为空列表)之后才抛出ConcurrentModificationException不是懒惰行为。如果我对迭代器做同样的操作-我将在ConcurrentModificationException之前只看到一个输出;
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();
    }
}
1