Clarification of BaseStream.onClose() behavior

Tagir F. Valeev amaembo at
Sat Jan 16 03:13:32 UTC 2016


Seems that my original letter sounds confusing due to my bad English.
Every occurrence of "idempotent" should be read as "not idempotent".
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?


Tagir Valeev.

PS> Thanks,
PS> Paul.

>> On 15 Jan 2016, at 05:35, Tagir F. Valeev <amaembo at> 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.

More information about the core-libs-dev mailing list