【问题标题】:How to implement Stream<E> without a resource leak warning in Java如何在 Java 中实现没有资源泄漏警告的 Stream<E>
【发布时间】:2019-05-25 17:57:32
【问题描述】:

我希望实现Stream&lt;E&gt; 接口(我承认,它是不必要的大接口)并添加一个构建器方法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();

StreamCloseable 行为有问题。 Stream 的文档说关于关闭(格式化我的):

流有一个BaseStream.close() 方法并实现AutoCloseable,但几乎所有流实例在使用后实际上都不需要关闭。一般只有源为 IO 通道的流(如Files.lines(Path, Charset)) 返回的流才需要关闭。

关闭 Stream 的唯一方法是 flatMapclose

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

资源泄漏:'&lt;unassigned Closeable value&gt;' 永远不会关闭

这无法通过 IntelliJIdea 2018.1.5 重现。我浏览的相关问题是herehere。我了解FileDictionaryCloseable 问题,但是,我坚持使用Streams。

我不喜欢调用私有构造函数的静态方法MyStream.of(...)

【问题讨论】:

  • 你试过给它类型参数吗?新的MyStream&lt;Long&gt;(list.stream())...
  • @DamianLattenero:而不是MyStream&lt;Integer&gt;,因为原点是List&lt;Integer&gt;。是的,我做到了,没有区别。
  • 我遇到了类似的问题,但在我的情况下不是Stream 接口的实现。相反,在 TotalCross 中,可以访问 Java 8 提供的功能接口(但不是默认方法或静态方法,只是抽象方法),但与 j.u.Stream 没有任何相似之处。因此,我实现了我自己版本的Stream(项目here),但有平台限制。我忘记添加 BaseStream 方法,所以我现在才注意到我的实现中没有任何 close...
  • 为了解决这个问题,我的类没有实现AutoCloseable,而是声明了一个方法close。还创建了一个StreamHolder 类,该类接收Stream 并且可自动关闭,调用Stream 关闭方法并允许检索原始Stream(尚未推送)
  • 出于好奇,我已经朝着这个目标推进了一些工作:gitlab.com/geosales-open-source/totalcross-functional-toolbox/-/… ;我是巴西人,主要讲葡萄牙语,我的同事也是讲葡萄牙语的巴西人,所以我在 repo/code 中的文字主要是葡萄牙语

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


【解决方案1】:

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 起)的类被认为代表外部资源,应该使用close() 方法关闭,当它们不再需要。

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

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

【讨论】:

  • 感谢您挖掘 javadoc 中的变化。不幸的是,这让我们没有类型声明它的所有实例应该被关闭。
  • @StephanHerrmann 我完全同意并感谢您作为内部人员的回答。
【解决方案2】:

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

  • 当程序员忘记关闭抗 GC (GCR) 资源(例如 FileInputStream)时,像 ecj 这样的工具会发出信号。

  • 图书馆团队计划将 java.util.Stream 设为 AutoCloseable 的子类型,以便在 try-with-resource 中使用,这是因为 j.u.Stream 可能可能由 GCR 资源支持。尽管如此,默认假设应该是j.u.Stream 的实例需要close() 调用。

  • 不过,java.nio 中的某些方法返回 j.u.Stream 要求close()d。

EG 和 Eclipse 一致认为,没有简单的解决方案可以仅通过查看可关闭对象的类型任何工具都可以精确识别 是否需要关闭。这是由于各种资源在多个级别包装其他资源的复杂性。特别是 j.u.Stream 类型没有给出实例是否由 GCR 资源支持的指示。

进一步提到,对于一个干净的解决方案,需要一个类型注释系统(使用 JSR 308)来丰富类型系统,其中包含精确静态分析所需的信息。据我所知,这种方法直到今天才成为现实。

作为一种折衷方案,建议 Eclipse 等工具实现者按照以下方式对启发式算法进行编码:

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

  • 以下已知类型集将从分析中排除,因为这些类型通常不需要关闭:java.util.Stream{Int,Long,Double}Stream

  • 作为例外的一个例外,java.nio 中的某些返回流的静态方法已知需要关闭。

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

历史就是这么多。

2013 年的讨论没有考虑到j.u.Stream自定义实现。 Eclipse 假定没有关于这些实现的特定知识。如果不是该工具会决定是否需要 close() 会更好,但如果实现者(此处为 MyStream)将有办法指示此类的实例是否需要关闭。然而,迄今为止的实现者无法表达这一点。

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

如 howlger 的回答所建议的那样,将警告标记为“潜在泄漏”会令人困惑,因为在流程分析中,“潜在”一词通常应该表示在某些(但不是全部)流经程序时发生的行为。

目前可用的选项有:

  • 在使用MyStream 的地方使用@SuppressWarnings("resource")(首选)

  • 降低此特定问题的严重性(如果 MyStream 的使用范围太广,无法使用第一个选项)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-24
    • 2012-12-07
    • 1970-01-01
    • 2016-09-23
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    相关资源
    最近更新 更多