为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

莫回无 2022-09-14 16:32:13
当您想要使用某些对象时,您应该使用试用资源。还行。但是,如果我想写方法,那会返回呢?在创建或从某个地方接收可自动关闭的对象后,您应该在发生异常时将其关闭,如下所示: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中做到这一点?
查看完整描述

1 回答

?
尚方宝剑之说

TA贡献1788条经验 获得超4个赞

有一些方法。

  • 使用“围绕执行”成语。重新制定接口以简化客户端实现并消除问题。

  • 忽略问题。听起来很愚蠢,但这通常是使用 I/O 流装饰器包装时发生的情况。

  • 包装在代理中,并将其放在试用资源中。AutoCloseable

  • 写出与资源一起尝试使用尝试捕获和尝试最终的等效项。(我不会 - 讨厌。

  • 将修改后的试用资源编写为库功能。此代码将成为执行周围的客户端。

  • 编写异常处理旧学校风格与尝试捕捉和尝试最终。

编辑:我想我会重新审视答案,添加一些示例代码来娱乐。

围绕成语执行

简单而最好的解决方案。不幸的是,Java库并不经常使用它(这是一个很大的例外),并且约定也没有很好地建立。与以往一样,Java在没有支持功能的情况下检查的异常使事情变得棘手。我们不能使用,必须发明我们自己的功能接口。AccessController.doPrivilegedjava.util.function

// Like Consumer, but with an exception.

interface Use<R, EXC extends Exception> {

    void use(R resource) throws EXC;

}


public static void withThing(String name, Use<InputStream,IOException> use) throws IOException {

     try (InputStream in = new FileInputStream(name)) {

         use.use(in);

     }

}

很好,很简单。无需担心客户端代码会弄乱资源处理,因为它不会这样做。好。


修改后的“使用资源试用”作为库功能,作为代理实现,可在“使用资源试用”中自动关闭


它会变得丑陋。我们需要将获取、发布和初始化作为 lambdas 传递。直接在此方法中创建资源将打开一个小窗口,其中意外的异常会导致泄漏。


public static InputStream newThing(String name) throws IOException {

    return returnResource(

        () -> new FileInputStream(name),

        InputStream::close,

        in -> {

            int ignore = in.read(); // some work

        }

    );

}

的一般实现将类似于下面的这个黑客。这是一个黑客,因为尝试资源不支持这种事情,Java库不支持检查异常。请注意,限制为一个例外(对于未选中的例外,可以使用未选中的例外)。returnResource


interface Acquire<R, EXC extends Exception> {

    R acquire() throws EXC;

}

// Effectively the same as Use, but different.

interface Release<R, EXC extends Exception> {

    void release(R resource) throws EXC;

}


public static <R, EXC extends Exception> R returnResource(

    Acquire<R, EXC> acquire, Release<R, EXC> release, Use<R, EXC> initialize

) throws EXC {

    try (var adapter = new AutoCloseable() { // anonymous classes still define type

        private R resource = acquire.acquire();

        R get() {

            return resource;

        }

        void success() {

            resource = null;;

        }

        public void close() throws EXC {

           if (resource != null) {

               release.release(resource);

           }

        }

    }) {

        R resource = adapter.get();

        initialize.use(resource);

        adapter.success();

        return resource;

    }

}

如果我们将构建资源的参数与资源的构造分开,这可能会更干净。


public static InputStream newThing(String name) throws IOException {

    return returnResource(

        name,

        FileInputStream::new,

        InputStream::close,

        in -> {

            int ignore = in.read(); // some work

        }

    );

}


// Like Function, but with a more descriptive name for a functional interface.

interface AcquireFrom<T, R, EXC extends Exception> {

    R acquire(T t) throws EXC;

}


public static <T, R, EXC extends Exception> R returnResource(

    T t, AcquireFrom<T, R, EXC> acquire, Release<R, EXC> release, Use<R, EXC> initialize

 ) throws EXC {

     return returnResource(() -> acquire.acquire(t), release, initialize);

 }

因此,总而言之,以下事情是痛苦的:

  • 转让资源所有权。将其保留在本地。

  • java.util.function不支持选中的异常。

  • Java 库不支持执行周围。

  • AutoCloseable::close声明它抛出而不是成为类型的类型参数。Exception

  • 已检查没有总和类型的异常。

  • 一般的 Java 语言语法。


查看完整回答
反对 回复 2022-09-14
  • 1 回答
  • 0 关注
  • 108 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号