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