如何在Java中实现Stream <e>而没有资源泄漏警告

时间:2018-12-27 18:48:43

标签: java eclipse memory-leaks java-8 java-stream

我希望实现Stream<E>接口(我承认这是不必要的大接口),并添加了一个生成器方法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.......);
    }  
}

到目前为止,一切都很好。

long count = new MyStream(list.stream())
    .map(i -> i * 10)
    .foo()
    .filter(i -> i > 100)
    .count();

我对Closeable的{​​{1}}行为有疑问。 Stream的文档中介绍了有关关闭(格式化我的)的信息:

  

流具有Stream方法并实现BaseStream.close(),但是实际上几乎所有流实例在使用后都不需要关闭。通常,只有源是IO通道的流(例如AutoCloseable返回的流)才需要关闭。

关闭Stream的唯一方法是Files.lines(Path, Charset))flatMap

Eclipse Oxygen 中的对象实例化带有以下警告:

  

资源泄漏:“ close”从未关闭

IntelliJIdea 2018.1.5 不能重现此问题。我略过的相关问题是herehere。我了解<unassigned Closeable value>Closeable的{​​{1}}问题,但是,我对Streams感到困惑。

我不喜欢调用私有构造方法的静态方法File

2 个答案:

答案 0 :(得分:3)

In Java 7 the description of AutoCloseable

  

“ ... 必须关闭 ...”

in Java 8 the description在语义上已更改为

  

“ ... 可以保存资源(例如文件或套接字句柄)...”

在Eclipse中,对于未关闭的所有CloseableAutoCloseable实例,资源泄漏警告均独立于Java版本显示(在您的示例中就是这种情况)。参见Eclipse help

  

考虑了实现接口java.io.Closeable(自JDK 1.5起)和java.lang.AutoCloseable(自JDK 1.7起)的类以表示外部资源,应使用方法{{ 1}},当不再需要它们时。

根据更改后的Javadoc描述,我希望在Java 8或更高版本中,未关闭的close()只会发出潜在资源泄漏警告,而不是资源泄漏 em>警告。 Eclipse JDT开发人员Stephan Herrmann,explains in his answer why he doesn't think this is a good idea

作为Java 8或更高版本的解决方法,将AutoCloseable添加到不必关闭@SuppressWarnings("resource")的那些地方。

答案 1 :(得分:3)

作为JSR 335工作的一部分,JRE库通过引入java.util.Stream而发展,同时在java.nio等地方利用了新概念。在此期间,JSR 335专家组与Eclipse团队进行了磋商,以讨论以下冲突

  • 诸如ecj之类的工具希望在程序员忘记关闭抗GC(GCR)资源(例如FileInputStream)时发出信号。

  • 图书馆团队计划将java.util.Stream设为AutoCloseable的子类型,以便在{-{1}}可以可能由GCR资源支持。仍然,默认假设应该是j.u.Stream的实例不需要进行j.u.Stream调用。

  • 仍然,close()中的某些方法返回java.nio的{​​{1}} 要求

EG和Eclipse同意,找不到简单的解决方案,这样仅通过查看可关闭对象的类型,任何工具都可以准确识别 >是否需要关闭。这是由于各种资源在多个级别上包装其他资源的复杂性。特别是类型j.u.Stream不能表示实例是否由GCR资源支持。

为获得清晰的结果,还需要使用类型注释系统(使用JSR 308),以使用精确的静态分析所需的信息来丰富类型系统。据我所知,这种方法直到今天才得以实现。

作为一种折衷,建议像Eclipse这样的工具实现者按照以下方式对启发式编码:

  • 通常,所有close()类型的实例都应关闭。

  • 以下已知类型集将从分析中排除,因为通常 不需要关闭:j.u.StreamAutoCloseable

  • 作为该异常的一个例外,已知java.util.Stream中某些返回Stream的静态方法 require 关闭。

讨论基本上发生在lambda-libs-spec-observers邮件列表上的以下两个帖子之间:

历史这么多。

2013年的讨论未考虑{Int,Long,Double}Stream自定义实现。 Eclipse假定没有关于那些实现的特定知识。最好是,如果不是这样,该工具将决定是否需要close()的偏见,但是如果实现者(在java.nio处)有办法表明,此类的实例是否需要关闭或不。但是,迄今为止的实现者没有办法表达这一点。

由于缺乏完整而精确的选择,我们可以讨论扩展启发式方法的集合,这样,不仅j.u.Stream系列中的已知类型集,而且还包括其所有子类型 >从分析中排除,并被认为是GC友好的。显然,这种方法会增加假阴性(分析遗漏的错误)的风险。

如霍尔格的答案所建议的那样,将警告标记为“潜在泄漏”将是令人困惑的,因为在流分析中,“潜在”一词通常应表示在整个程序中(但不是全部)发生的行为。

截止到今天,可用的选项是:

  • 在使用MyStream的任何地方使用j.u.Stream(首选)

  • 降低此特定问题的严重性(如果使用@SuppressWarnings("resource")的使用范围太广而无法使用第一种选择)。