How to implement Stream<E> without a resource leak warning in Java

会有一股神秘感。 提交于 2020-06-24 14:15:09

问题


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 implement AutoCloseable, 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 by Files.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.


回答1:


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).




回答2:


In Java 7 the description of AutoCloseable is

"...must be closed..."

whereas in Java 8 the description was semantically changed to

"...that may hold resources (such as file or socket handles)..."

In Eclipse the resource leak warning is shown independent of the Java version for all Closeable and AutoCloseable instances that are not being closed (which is the case in your example). See Eclipse help:

Classes implementing the interface java.io.Closeable (since JDK 1.5) and java.lang.AutoCloseable (since JDK 1.7) are considered to represent external resources, which should be closed using method close(), when they are no longer needed.

According to the changed Javadoc description, I would expect in Java 8 or higher for a not closed AutoCloseable only a Potential Resource Leak warning instead of a Resource Leak warning. Stephan Herrmann, an Eclipse JDT developer, explains in his answer why he doesn't think this is a good idea.

As a workaround for Java 8 or higher, add @SuppressWarnings("resource") to those places where the AutoCloseable does not have to be closed.



来源:https://stackoverflow.com/questions/53949538/how-to-implement-streame-without-a-resource-leak-warning-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!