Hello!

Here's a webrev:
http://cr.openjdk.java.net/~tvaleev/webrev/8147505/r1/

I just added a check in AbstractPipeline.onClose and the corresponding
unit-test. To me it seems that no documentation corrections are
necessary, because "onClose" is already documented that it's
an intermediate operation:

http://download.java.net/jdk9/docs/api/java/util/stream/BaseStream.html#onClose-java.lang.Runnable-

Also it's already documented:

> A stream should be operated on (invoking an intermediate or terminal
> stream operation) only once. This rules out, for example, "forked"
> streams, where the same source feeds two or more pipelines, or
> multiple traversals of the same stream. A stream implementation may
> throw IllegalStateException if it detects that the stream is being
> reused.

http://download.java.net/jdk9/docs/api/java/util/stream/Stream.html

So this already implies that invoking intermediate operation "onClose"
after stream terminal operation is not allowed and may throw
IllegalStateException.

Please review!

With best regards,
Tagir Valeev.

TFV> Seems that my original letter sounds confusing due to my bad English.
TFV> Every occurrence of "idempotent" should be read as "not idempotent".
TFV> Sorry for this!

PS>> We did not bother to throw ISEs from parallel/sequence/onClose
PS>> primarily because they return “this” and they are kind of
PS>> harmless, but the undefined behaviour you point out could be shut
PS>> down without much concern for backwards compatibility. We can
PS>> modify them to check whether they have been linked or consumed
PS>> (while not updating the previous stage).

PS>> Wanna log an issue?

TFV> Sure:
TFV> https://bugs.openjdk.java.net/browse/JDK-8147505

TFV> Thanks,
TFV> Tagir Valeev.

PS>> Thanks,
PS>> Paul.


>>> On 15 Jan 2016, at 05:35, Tagir F. Valeev <amae...@gmail.com> wrote:
>>> 
>>> Hello!
>>> 
>>> Current documentation for BaseStream.onClose() does not specify
>>> explicitly how the stream would behave if additional close handlers
>>> are registered after the stream is consumed or even closed. The
>>> implementation actually allows registering the additional close
>>> handlers after consumption or closure and close() method is
>>> idempotent: newly registered handlers are perfectly called:
>>> 
>>> Stream<String> s = Stream.of("content");
>>> s = s.onClose(() -> System.out.println("A"));
>>> s.forEach(System.out::println);
>>> s = s.onClose(() -> System.out.println("B"));
>>> s.close(); // prints A and B
>>> s = s.onClose(() -> System.out.println("C"));
>>> s.close(); // prints C
>>> 
>>> (removing "s =" produces the same result).
>>> 
>>> I think if such behavior is intended, it should be explicitly noted in
>>> the specification, as third-party implementations of BaseStream
>>> interface should provide consistent behavior. Or at least it should be
>>> noted that some BaseStream implementations may have idempotent close()
>>> method, so the derived AutoCloseable objects (which own the BaseStream
>>> object) should be aware about this behavior and provide idempotent
>>> close() method as well. Without knowing this one may write:
>>> 
>>> class MyObject implements AutoCloseable {
>>>  private BaseStream<?, ?> s;
>>> 
>>>  public MyObject(BaseStream<?, ?> s) {
>>>    this.s = s;
>>>  }
>>> 
>>>  @Override
>>>  public void close() throws Exception {
>>>    if(s != null) {
>>>      s.close();
>>>      s = null;
>>>    }
>>>  }
>>> }
>>> 
>>> Such code closes the stream only once, so newly registered handlers
>>> will not be called if MyObject::close is called the second time.
>>> 
>>> However, to my opinion the current behavior is weird and should be
>>> changed in order not to allow registering new close handles (throwing
>>> IllegalStateException) when the stream is already closed, or even
>>> better when the stream is linked/consumed. As far as I know currently
>>> in JDK close handlers are registered only for non-consumed stream, so
>>> such change would not break existing JDK code (though may break some
>>> strange third party code). It should be noted that AutoCloseable
>>> interface discourages idempotent close() methods (though not forbids
>>> them).
>>> 
>>> What do you think?
>>> 
>>> With best regards,
>>> Tagir Valeev.
>>> 

Reply via email to