简体   繁体   English

AutoCloseable contract:写入close()允许的资源?

[英]AutoCloseable contract: writing to resource allowed in close()?

I've stumbled across the following construct in-house: 我偶然发现了内部的以下构造:

class OurXmlWriter implements AutoCloseable {
    private XMLStreamWriter streamWriter;
    public OurXmlWriter(OutputStream stream) {
        streamWriter = XMLOutputFactory.newInstance()
                        .createXMLStreamWriter(outputStream, "UTF-8");
    }

    @Override
    public void close() {
        try {
            // is this allowed?
            streamWriter.writeEndDocument();
        } catch (XMLStreamException e) {
            throw new RuntimeException();
        } finally {
            try {
                streamWriter.close();
            } catch (XMLStreamException e) {
                throw new RuntimeException();
            }
            streamWriter = null;
        }
    }
}

The problem we've had with this is: 我们遇到的问题是:

try (OurXmlWriter writer = new OurXmlWriter(new FileOutputStream("output.xml"))) {
    writer.writeStartTag();
    // write some data elements correctly
    throw new OutOfMemoryError(); // that's not done explicitly but happens
}

This still calls close() - which is fine as such but results in the xml being closed correctly (albeit unreliably because I'm sure it's not guaranteed to succeed after an Error ). 这仍然调用close() - 这样就可以了,但是会导致xml正确关闭(虽然不可靠,因为我确信它不能保证在Error后成功)。

So the issue is basically that the XML is valid although we'd prefer it not be (so the output is not accidentally processed further in case the Error is missed). 所以问题基本上是XML是有效的,尽管我们不喜欢它(因此在错过错误的情况下不会意外地处理输出)。 I'm pondering on how to best approach the situation - remove the end tag writing from close() - which would require a lot of analysis retesting - or just not use try-with-resource to have control over whether it is called. 我正在思考如何最好地处理这种情况 - 从close()删除结束标记 - 这需要大量的分析重新测试 - 或者只是不使用try-with-resource来控制它是否被调用。

But the general question I have is: Does the AutoCloseable contract allow to still write into your resources when you're told to close() ? 但我的一般问题是:当你被告知close()时, AutoCloseable合约是否允许仍然写入你的资源? I've been reading the javadoc but it doesn't really explicitly disallow it. 我一直在阅读javadoc,但它并没有真正明确禁止它。 Am I missing something? 我错过了什么吗?

Basically there's nothing in the Javadoc to indicate it wouldn't be allowed, and in fact it says that 基本上Javadoc中没有任何东西表明它不会被允许,事实上它说的是

Note that unlike the close method of java.io.Closeable this close method is not required to be idempotent. 请注意,与close的方法java.io.Closeableclose 不需要方法为幂等。 In other words, calling this close method more than once may have some visible side effect, unlike Closeable.close which is required to have no effect if called more than once. 换句话说,不止一次调用此close方法可能会产生一些可见的副作用,这与Closeable.close不同,如果多次调用则需要它无效。

which allows for side effects and doesn't even require the method to be idempotent. 这允许副作用,甚至不要求该方法是幂等的。 Considering that writing the end of the document is a relatively unsurprising side effect, I'd say that's alright. 考虑到写文档的结尾是一个相对不令人惊讶的副作用,我会说没关系。 But of course just because it's not forbidden doesn't mean it's allowed, YMMV, opinion based, consult your in-house rulebook etc. 但当然只是因为它不被禁止并不意味着它是允许的,YMMV,基于意见,咨询你的内部规则手册等。

There are examples in the Java Standard class libraries where the close() method has to perform a write. Java Standard类库中有一些示例,其中close()方法必须执行写操作。 One such example is DeflaterOutputStream whose javadoc states: 一个这样的例子是DeflaterOutputStream它的javadoc状态:

Writes remaining compressed data to the output stream and closes the underlying stream. 将剩余的压缩数据写入输出流并关闭基础流。

The point being that the last bit of a compressed stream can only be when you know that the stream is being closed. 关键是压缩流的最后一位只能在您知道流被关闭时才会出现。 Flushing is not sufficient. 冲洗是不够的。

So combine this with @Kayaman and there is clear evidence that it is permitted for a stream to perform a write during close() . 因此将它与@Kayaman结合使用,并且有明确证据表明允许流在close()期间执行写入。

(And another example would be BufferedOutputStream where close() does the equivalent of a flush() call if required.) (另一个例子是BufferedOutputStream ,其中close()在需要时执行相当于flush()调用。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM