I wish to implement the Stream<E>
interface (I admit, it's the unnecessarily large one) and add a builder method foo()
.
public MyStream<E> implements Stream<E>, ExtendedStream<E> {
private final Stream<E> delegate;
public MyStream(final Stream<E> stream) {
this.delegate = stream;
}
// a sample Stream<E> method implementation
@Override
public <R> MyStream<R> map(Function<? super E, ? extends R> mapper) {
return new MyStream<>(this.delegate.map(mapper));
}
// the rest in the same way (skipped)
// a method from ExtendedStream<E>
@Override
public MyStream<E> foo() {
return new MyStream(this.delegate.......);
}
}
So far so good.
long count = new MyStream(list.stream())
.map(i -> i * 10)
.foo()
.filter(i -> i > 100)
.count();
I have trouble with the Closeable
behavior of Stream
. The documentation of Stream
says about closing (formatting mine):
Streams have a
BaseStream.close()
method and implementAutoCloseable
, but nearly all stream instances do not actually need to be closed after use. Generally, only streams whose source is an IO channel (such as those returned byFiles.lines(Path, Charset))
will require closing.
The only methods that close Stream are flatMap
or close
.
The instantiation of an object in Eclipse Oxygen is underlined with a warning:
Resource leak: '
<unassigned Closeable value>
' is never closed
This is not reproducible with IntelliJIdea 2018.1.5. Related questions I skimmed through are here and here. I understand the Closeable
issues with File
or Dictionary
, however, I am stuck with Streams.
I dislike the static method MyStream.of(...)
calling a private constructor workaround.
Unclosed Resources Such code requires opening a stream, connection, or file inside our code. But we have to remember that we are the ones responsible not only for opening the resource but also for closing it. Otherwise, our code can leak memory, eventually leading to OutOfMemory error.
In general, a Java memory leak happens when an application unintentionally (due to logical errors in code) holds on to object references that are no longer required. These unintentional object references prevent the built-in Java garbage collection mechanism from freeing up the memory consumed by these objects.
As part of work on JSR 335, the JRE libraries evolved by introducing java.util.Stream
and at the same time leveraging the new concept in places like java.nio
. During this time the Eclipse team was consulted by the JSR 335 expert group, to discuss the following conflict:
Tools like ecj want to signal when programmers forget to close a GC-resistent (GCR) resource like, e.g., a FileInputStream
.
The library team planned to make java.util.Stream
a subtype of AutoCloseable
to enable usage in try-with-resource, motivated by the fact that a j.u.Stream
could potentially be backed by a GCR resource. Still, the default assumption should be that instances of j.u.Stream
do not require a close()
call.
Still, certain methods in java.nio
returning j.u.Stream
require to be close()
d.
EG and Eclipse agreed, that no easy solution could be found such that just by looking at the type of closeable any tool could precisely recognize whether closing is necessary or not. This is due to intricacies of various resources wrapping other resources at several levels. In particular the type j.u.Stream
gives no indication whether or not instances are backed by GCR resources or not.
For a clean solution, it was further mentioned, that a system of type annotations (using JSR 308) would be needed to enrich the type system with the information needed for precise static analysis. To the best of my knowledge, such approach hasn't materialized until today.
As a compromise, tool implementors like Eclipse were advised to encode heuristics along the following lines:
Normally, all instances of type AutoCloseable
should be closed.
The following known set of types was to be excluded from the analysis, because those typically do not require closing: java.util.Stream
and {Int,Long,Double}Stream
.
As an exception from the exception, certain Stream-returning static methods in java.nio
are known to require closing.
The discussion basically happened between the following two posts on the lambda-libs-spec-observers mailing list:
Brian's problem statement & intermediate proposal
My summary of a private discussion.
So much for the history.
The discussion in 2013 did not account for custom implementations of j.u.Stream
. Eclipse assumes no specific knowledge about those implementations. It would be better, if not the tool would decide a bias towards needing / not needing close(), but if the implementor (here of MyStream
) would have the means to indicate, whether instances of this class require closing or not. To-date implementors have, however, no means to express this.
For lack of a complete and precise option, we could discuss extending the set of heuristics, such that not only the known set of types in the j.u.Stream
family, but also all its subtypes are excluded from the analysis, and considered to be GC-friendly. Obviously, such approach would increase the risk of false negatives (bugs missed by the analysis).
Marking warnings as "potential leaks", as suggested by howlger's answer would be confusing, because in flow-analysis, the word "potential" should normally indicate a behavior that occurs on some, but not all, flows through the program.
Available options as of today are:
Using @SuppressWarnings("resource")
wherever MyStream
is used (preferable)
Lowering the severity of this particular problem (if use of MyStream
is too wide spread for using the first option).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With