V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
narutow
V2EX  ›  Java

Java 读写 Stream 时, 如果 close 失败了, 应该怎样保证 Stream 最终会被关闭呢?

  •  
  •   narutow · 2021-03-12 10:20:12 +08:00 · 3518 次点击
    这是一个创建于 1356 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用下面的 java 代码读写流, 如果 close 发生了异常, 怎么保证流一定会被关闭呢? 还是说 close 都出错了, 那么就不管了, 直接挂掉?

    OutputStream out = null;
    try {
        out = new FileOutputStream("");
        // ...操作流代码
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if (out != null) {
                out.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    17 条回复    2021-03-13 16:32:39 +08:00
    urzz
        1
    urzz  
       2021-03-12 10:28:46 +08:00
    用 try-with-resources
    zpf124
        2
    zpf124  
       2021-03-12 10:29:02 +08:00
    一般都是 close 抛异常不怎么处理,甚至错误打印有时候都没有。

    因为 close 一般报错都是 流已经被关闭的错误。
    比如你在其他地方已经执行过一次 close 了或者流的另一端已经直接端口了。
    xiecanmy
        3
    xiecanmy  
       2021-03-12 10:35:34 +08:00
    用 try-with-resources


    try(OutputStream out = new FileOutputStream("")) {

    // ...操作流代码
    } catch (Exception e) {
    e.printStackTrace();
    }
    Oktfolio
        4
    Oktfolio  
       2021-03-12 10:35:40 +08:00
    try (OutputStream out = new FileOutputStream("")) {

    } catch (Exception e) {
    e.printStackTrace();
    }
    RedBeanIce
        5
    RedBeanIce  
       2021-03-12 10:38:13 +08:00
    因为 finally 一定会执行。。。
    RedBeanIce
        6
    RedBeanIce  
       2021-03-12 10:38:46 +08:00   ❤️ 4
    我错了。我傻子。请不要看我。
    narutow
        7
    narutow  
    OP
       2021-03-12 10:39:11 +08:00
    @RedBeanIce 是的, 但如果写在 finally 中的 close 再抛异常, 说明 close 失败了, 这时候该怎么处理呢
    RedBeanIce
        8
    RedBeanIce  
       2021-03-12 10:46:55 +08:00   ❤️ 1
    @narutow 请看 6 楼,我是傻子我是傻子我是傻子
    Still4
        9
    Still4  
       2021-03-12 12:20:12 +08:00
    finally 最好只放最简单的逻辑,比如断开连接,直接变量置空,干净利落的切掉

    你这个例子里面,不得不调用可能抛出异常的代码,只能无视了,还能咋办呢....
    iseki
        10
    iseki  
       2021-03-12 12:27:19 +08:00 via Android
    一般不处理吧,你不能无限兜底,另外如果 finally 里抛了异常会被抑制,见 suppress
    ychost
        11
    ychost  
       2021-03-12 12:34:31 +08:00
    1. try-with-resource
    2. lombok @Clean
    当然都无法解决你说的问题,在 finally 里面 抛异常了,不能无限兜底的
    hantsy
        12
    hantsy  
       2021-03-12 14:32:36 +08:00
    以为是 Stream API 。

    IO Stream 基本都是可以 Try (初始化 Stream ){},主要看它是否实现 Closable 接口。
    newmlp
        13
    newmlp  
       2021-03-12 14:59:02 +08:00
    close 不可能失败的,
    Brentwans
        14
    Brentwans  
       2021-03-12 15:44:42 +08:00
    大概明白你的疑问,你的问题应该是异常处理没弄明白。这里 close 失败的异常,是让处理后事用的。假设,你的输出流是将新增的内存数据持久化写到磁盘用的。close 关闭失败,意味着持久化失败了,这个时候可能的处理是将新增加的数据对象从内存删除,恢复到添加之前的样子。
    需要强制处理的异常,通常是处理后事用的,下层没处理最好还是抛出上层处理。二话不说默认异常输出到日志,这个代码会有问题的。
    cheng6563
        15
    cheng6563  
       2021-03-12 17:41:36 +08:00   ❤️ 1
    IO Stream 的 close()的异常,基本上都不是关闭连接产生的异常而是重复关闭连接产生的。
    dreamist
        16
    dreamist  
       2021-03-12 17:42:51 +08:00   ❤️ 1
    首先,try-with-resource 并不能解决这个问题,因为它本质上是编译器的语法糖,和自己写 try catch finally 一样的。然后关于这个问题,如果真的出现了 close 也也出现异常的情况,那么其实是没有什么好的办法的了,无法再确定它内部是不是真的关闭了的。
    ikas
        17
    ikas  
       2021-03-13 16:32:39 +08:00
    假设 close 出错了,那这个错误可能会对将来的执行造成影响,这时候,错误还是会产生,还是有机会再见的~,这时候就会来检查,为啥关闭不了~,如果是业务有要求,那么关闭的时候出错,你必然是要做处理的,或者继续 throw
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3251 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 13:01 · PVG 21:01 · LAX 05:01 · JFK 08:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.