Java流关闭方法不明确的行为

Java流关闭方法不明确的行为,java,java-8,stream,java-stream,Java,Java 8,Stream,Java Stream,给定这个Java类: class MyClass { private int value; public MyClass(int value) { this.value = value; } public void setValue(int value) { this.value = value; } public int getValue() { return this.value;

给定这个Java类:

class MyClass {
    private int value;

    public MyClass(int value) {
        this.value = value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }

    @Override
    public String toString() {
        return "Value: " + value;
    }
}
给出以下Java代码:

Consumer<MyClass> cons = mc -> mc.setValue(mc.getValue() * mc.getValue());

List<MyClass> list = new ArrayList<>();
list.add(new MyClass(1));
list.add(new MyClass(2));
list.add(new MyClass(3));

System.out.println(list);
我希望得到输出[Value:1,Value:4,Value:9],但得到的却是[Value:1,Value:2,Value:3], 因此列表中的元素没有被修改

但当我运行这个:

list.stream().forEach(cons);        //2
这是:

list.stream().peek(cons).count();   //3
我两次都得到了预期的输出([Value:1,Value:4,Value:9])

为什么第//1行没有给我这个输出?我想这是因为close():这个方法是如何工作的


感谢您的支持。

peek
是一种中间操作,除非您有终端操作员,否则不会触发流处理管道。那么这个声明,

list.stream().peek(cons).close();
没有终端操作,并且根本不会触发流管道,因此不会执行使用者,从而导致您观察到的结果。该名单未作修改。但是,这不是由于streams中的
close
方法造成的

在其他两种情况下

list.stream().forEach(cons);        
list.stream().peek(cons).count();  

您有终端操作
forEach
count
,因此执行消费者导致修改原始列表。

peek
是一个中间操作,除非您有终端操作符,否则不会触发流处理管道。那么这个声明,

list.stream().peek(cons).close();
没有终端操作,并且根本不会触发流管道,因此不会执行使用者,从而导致您观察到的结果。该名单未作修改。但是,这不是由于streams中的
close
方法造成的

在其他两种情况下

list.stream().forEach(cons);        
list.stream().peek(cons).count();  

您有每个和计数的终端操作,因此消费者被执行,导致修改原始列表。

关闭
,无论是否有终端操作都将被触发;如果它用于
try with resource
close
流本身被调用;但不管怎样,这都不是一个终端操作。所以它既不是中间的,也不是终端的,它有点特别

    Stream<Integer> s2 = Stream.of(1, 2, 3);
    s2.onClose(() -> System.out.println("Closing 2"));
    s2.close(); // will print Closing 2
streams2=Stream.of(1,2,3);
s2.onClose(()->System.out.println(“Closing 2”);
s2.close();//将打印结束2
但也看到了这一点:

    try (Stream<Integer> s = Stream.of(1, 2, 3)) {
        s.onClose(() -> System.out.println("Closing"));
        s.filter(x -> x > 1)
         .peek(x -> System.out.println("foud one"));
    }
try(streams=Stream.of(1,2,3)){
s、 onClose(()->System.out.println(“关闭”);
s、 过滤器(x->x>1)
.peek(x->System.out.println(“foud-one”);
}
运行此命令,亲自查看第二个示例中的
peek
未被触发,但
close
被触发


因此,为了回答您的问题,正确的措辞应该是:
close
不是终端操作,因此您的流管道不会执行

关闭
,无论是否有终端操作都会触发;如果它用于
try with resource
close
流本身被调用;但不管怎样,这都不是一个终端操作。所以它既不是中间的,也不是终端的,它有点特别

    Stream<Integer> s2 = Stream.of(1, 2, 3);
    s2.onClose(() -> System.out.println("Closing 2"));
    s2.close(); // will print Closing 2
streams2=Stream.of(1,2,3);
s2.onClose(()->System.out.println(“Closing 2”);
s2.close();//将打印结束2
但也看到了这一点:

    try (Stream<Integer> s = Stream.of(1, 2, 3)) {
        s.onClose(() -> System.out.println("Closing"));
        s.filter(x -> x > 1)
         .peek(x -> System.out.println("foud one"));
    }
try(streams=Stream.of(1,2,3)){
s、 onClose(()->System.out.println(“关闭”);
s、 过滤器(x->x>1)
.peek(x->System.out.println(“foud-one”);
}
运行此命令,亲自查看第二个示例中的
peek
未被触发,但
close
被触发


因此,为了回答您的问题,正确的措辞应该是:
close
不是终端操作,因此您的流管道不会执行

因为close()不是一个终端操作。它不会消耗流@我根本没有意识到“亲密的听众”这件事。
close()
是否保证在终端操作后调用?@daniu@daniu…因为close()不是终端操作。它不会消耗流@我根本没有意识到“亲密的听众”这件事。
close()
是否保证在终端操作后调用?@daniu@daniu…嗯--嗯。。。但如果显式调用,然后通过
try with resource
或终端操作调用,则可能会多次调用它,对吗?因此,您必须注意注册的
可运行的
具有幂等行为。@daniu-否,终端操作不会触发
关闭
;然后,无论您调用close多少次,
Runnable
只会触发一次,在内部有一个类似于was close的标志,
close
不是一个终端操作,但这没有抓住要点。即使它是一个终端操作,也并不意味着传递给
peek
的操作被执行,因为
peek
应该调试元素的处理,而
close
不需要处理任何元素。看看OP的第三个示例,
list.stream().peek(cons.count()。它碰巧处理Java 8中的所有元素,但从Java 9开始,它将在不处理任何元素的情况下提供答案,因此,不会执行传递给
peek
的操作。因此,作为一个终端操作并不意味着执行该操作…@霍尔格说得对,这只是为了证明终端操作被执行的观点,但我完全同意,我在解释时应该依赖终端操作本身的副作用。像往常一样,非常值得注意的是,
onClose
是一个中间操作,应该像所有其他中间操作一样使用,也就是说,您应该使用调用的结果:
s2=s2.onClose(()->System.out.println(“Closing 2”)
或者将后续操作直接链接到它,比如
s2.onClose()->System.out.println(“Clos