猿问

异常安全返回自动关闭的对象

当您想要使用某些对象时,您应该使用试用资源。还行。但是,如果我想写方法,那会返回呢?在创建或从某个地方接收可自动关闭的对象后,您应该在发生异常时将其关闭,如下所示:AutoClosableAutoClosable


    public static AutoCloseable methodReturningAutocloseable() {

        AutoCloseable autoCloseable = ... // create some AutoClosable

        try {

            ... // some work

        }

        catch (Throwable exception) {

            autoCloseable.close();

            throw exception;

        }

        return autoCloseable;

    }

如果你不写块,你会泄漏资源,该自动关闭的对象将保持不变,以防出现异常。但这还不够,因为也可以抛出异常(根据设计)。因此,上面的代码将转换为try/catch// some worktry/catchautoCloseable.close()


    public static AutoCloseable methodReturningAutocloseable() {

        AutoCloseable autoCloseable = ... // create some autoclosable

        try {

            ... // some work

        }

        catch (Throwable exception) {

            try {

                autoCloseable.close();

            }

            catch (Throwable exceptionInClose) {

                exception.addSuppressed(exceptionInClose);

                throw exception;

            }

            throw exception;

        }

        return autoCloseable;

    }

这是很多样板。有没有更好的方法来在java中做到这一点?


莫回无
浏览 109回答 1
1回答

尚方宝剑之说

有一些方法。使用“围绕执行”成语。重新制定接口以简化客户端实现并消除问题。忽略问题。听起来很愚蠢,但这通常是使用 I/O 流装饰器包装时发生的情况。包装在代理中,并将其放在试用资源中。AutoCloseable写出与资源一起尝试使用尝试捕获和尝试最终的等效项。(我不会 - 讨厌。将修改后的试用资源编写为库功能。此代码将成为执行周围的客户端。编写异常处理旧学校风格与尝试捕捉和尝试最终。编辑:我想我会重新审视答案,添加一些示例代码来娱乐。围绕成语执行简单而最好的解决方案。不幸的是,Java库并不经常使用它(这是一个很大的例外),并且约定也没有很好地建立。与以往一样,Java在没有支持功能的情况下检查的异常使事情变得棘手。我们不能使用,必须发明我们自己的功能接口。AccessController.doPrivilegedjava.util.function// Like Consumer, but with an exception.interface Use<R, EXC extends Exception> {&nbsp; &nbsp; void use(R resource) throws EXC;}public static void withThing(String name, Use<InputStream,IOException> use) throws IOException {&nbsp; &nbsp; &nbsp;try (InputStream in = new FileInputStream(name)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;use.use(in);&nbsp; &nbsp; &nbsp;}}很好,很简单。无需担心客户端代码会弄乱资源处理,因为它不会这样做。好。修改后的“使用资源试用”作为库功能,作为代理实现,可在“使用资源试用”中自动关闭它会变得丑陋。我们需要将获取、发布和初始化作为 lambdas 传递。直接在此方法中创建资源将打开一个小窗口,其中意外的异常会导致泄漏。public static InputStream newThing(String name) throws IOException {&nbsp; &nbsp; return returnResource(&nbsp; &nbsp; &nbsp; &nbsp; () -> new FileInputStream(name),&nbsp; &nbsp; &nbsp; &nbsp; InputStream::close,&nbsp; &nbsp; &nbsp; &nbsp; in -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int ignore = in.read(); // some work&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; );}的一般实现将类似于下面的这个黑客。这是一个黑客,因为尝试资源不支持这种事情,Java库不支持检查异常。请注意,限制为一个例外(对于未选中的例外,可以使用未选中的例外)。returnResourceinterface Acquire<R, EXC extends Exception> {&nbsp; &nbsp; R acquire() throws EXC;}// Effectively the same as Use, but different.interface Release<R, EXC extends Exception> {&nbsp; &nbsp; void release(R resource) throws EXC;}public static <R, EXC extends Exception> R returnResource(&nbsp; &nbsp; Acquire<R, EXC> acquire, Release<R, EXC> release, Use<R, EXC> initialize) throws EXC {&nbsp; &nbsp; try (var adapter = new AutoCloseable() { // anonymous classes still define type&nbsp; &nbsp; &nbsp; &nbsp; private R resource = acquire.acquire();&nbsp; &nbsp; &nbsp; &nbsp; R get() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return resource;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; void success() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resource = null;;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public void close() throws EXC {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (resource != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;release.release(resource);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }) {&nbsp; &nbsp; &nbsp; &nbsp; R resource = adapter.get();&nbsp; &nbsp; &nbsp; &nbsp; initialize.use(resource);&nbsp; &nbsp; &nbsp; &nbsp; adapter.success();&nbsp; &nbsp; &nbsp; &nbsp; return resource;&nbsp; &nbsp; }}如果我们将构建资源的参数与资源的构造分开,这可能会更干净。public static InputStream newThing(String name) throws IOException {&nbsp; &nbsp; return returnResource(&nbsp; &nbsp; &nbsp; &nbsp; name,&nbsp; &nbsp; &nbsp; &nbsp; FileInputStream::new,&nbsp; &nbsp; &nbsp; &nbsp; InputStream::close,&nbsp; &nbsp; &nbsp; &nbsp; in -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int ignore = in.read(); // some work&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; );}// Like Function, but with a more descriptive name for a functional interface.interface AcquireFrom<T, R, EXC extends Exception> {&nbsp; &nbsp; R acquire(T t) throws EXC;}public static <T, R, EXC extends Exception> R returnResource(&nbsp; &nbsp; T t, AcquireFrom<T, R, EXC> acquire, Release<R, EXC> release, Use<R, EXC> initialize&nbsp;) throws EXC {&nbsp; &nbsp; &nbsp;return returnResource(() -> acquire.acquire(t), release, initialize);&nbsp;}因此,总而言之,以下事情是痛苦的:转让资源所有权。将其保留在本地。java.util.function不支持选中的异常。Java 库不支持执行周围。AutoCloseable::close声明它抛出而不是成为类型的类型参数。Exception已检查没有总和类型的异常。一般的 Java 语言语法。
随时随地看视频慕课网APP

相关分类

Java
我要回答