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

InputStream 必须用 try/catch 捕捉?

  •  
  •   Richard14 · 2022-07-18 14:36:53 +08:00 · 3159 次点击
    这是一个创建于 877 天前的主题,其中的信息可能已经有所发展或是发生改变。

    根据廖雪峰教学文章中提供的代码,

    https://www.liaoxuefeng.com/wiki/1252599548343744/1298069163343905

    我在使用 FileInputStrem 打开和关闭文件时都必须添加 trycatch

    InputStream input = new FileInputStream("src/readme.txt");
    input.close()
    

    否则编译器就会提示 java: 未报告的异常错误 java.io.FileNotFoundException; 必须对其进行捕获或声明以便抛出。这导致一个读取文件的逻辑要三次 trycatch ,非常不优雅。

    根据其后文的描述可以采用

    try (InputStream input = new FileInputStream("src/readme.txt")) {
    }
    

    的方式让编译器自动补全 finally 后的 close ,但是我尝试其代码编译器仍提示必须捕捉 Exception 。

    请问这是由于 jdk 版本不同引发的从错误吗? javaer 正常打开和关闭文件的姿势是什么样的

    21 条回复    2022-07-19 22:31:33 +08:00
    dcsuibian
        1
    dcsuibian  
       2022-07-18 14:38:21 +08:00
    try{

    }catch(Exception e){
    throw new RuntimeException(e);
    }
    seanzxx
        2
    seanzxx  
       2022-07-18 14:41:47 +08:00
    正常的呀,Java 有一种叫做 checked exception 的东西,就是一定要处理,否则编译不过
    你这个打开读到的语句至少有两种异常要处理,FileNotFoundException, IOException
    857681664
        3
    857681664  
       2022-07-18 14:44:15 +08:00
    1. java 的几个关于 ioexception 的都是 checkedException, 需要显示捕获或者在调用方法上声明 throws, 如果觉得分开 3 次 try catch 繁琐,可以把几个 io 操作放一个大的 try catch 里
    2. try-with-resource 语法是 jdk1.7 之后才有的,你可以看一下自己的 jdk 版本是否符合要求,如果是用 IDEA, 看看是否设置了 language level 是不是 1.7+
    chendy
        4
    chendy  
       2022-07-18 14:46:44 +08:00
    try with resources 是编译器自动补全 finally 后的 close ,并没有补 catch ,所以还是需要自己 catch 的
    Zerek
        5
    Zerek  
       2022-07-18 14:47:54 +08:00
    有个东西叫做 lombok

    https://blog.51cto.com/attilax2/3655310
    //Lombok ?
    对冗长的 try/catch/finally 的一次包
    清单 6. 使用 @Cleanup 注释
    public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    //write file code goes here
    }
    Jwyt
        6
    Jwyt  
       2022-07-18 14:48:05 +08:00
    三次 trycatch 是怎么来的?
    像这种文本文件我都是 Files.readString()一把梭

    try (InputStream input = new FileInputStream("src/readme.txt")) {
    }
    这种写法是 try-with-resource, 你用这种就不用手动执行 close 操作了,也只是一次 trycatch 阿,哪来的三次?
    dcsuibian
        7
    dcsuibian  
       2022-07-18 14:52:16 +08:00   ❤️ 1
    @dcsuibian 转成 RuntimeException 然后抛,或者打印一下日志再抛。留给最上层处理。

    Java 的检查型异常是个没啥用的东西,其它语言都没有采用这种机制( C++:???)。
    最不实用的地方在于:就算你捕获到了这个异常,你也不知道怎么处理。

    网络、文件很容易出问题,但出问题了咋整,再试几次?试过几次还是不行呢?万一在 close 的时候出现异常呢?
    看看那些 ORM 框架、或者文件操作工具库,很明显底层一定会有 IO 操作,但他们就不会在方法上加一堆 throws 。
    XXWHCA
        8
    XXWHCA  
       2022-07-18 16:08:10 +08:00
    Java 的 io 操作就按着模版代码写吧,没有什么好办法,流读写,关闭输入输出流,三次 try-catch 是最基本的,最多使用 StreamUtil.close(stream)。
    大部分流都是需要 close 的,只有一部分内存流可以忽略,例如 ByteArrayXxxStream ,StringReader 等。
    像文件读写复制什么的,只能靠工具方法来减少模版代码的编写
    matepi
        9
    matepi  
       2022-07-18 16:41:02 +08:00
    @dcsuibian 要么抓明确的 IOException ,要抓上层就抓 Throwable ,抓 Exception 总感觉会漏

    可以看一下这里,为什么要抓 Throwable
    https://www.v2ex.com/t/638609
    dcsuibian
        10
    dcsuibian  
       2022-07-18 19:38:21 +08:00
    @matepi 随手写的,平时用的就是具体异常(反正 try/catch 是 IDE 写的)。

    Exception 比起 Throwable 来说,漏掉的就是 Error 。但 Error 本身就是那些严重到程序员无法处理的错误了。
    [When to catch java.lang.Error?]( https://stackoverflow.com/questions/352780/when-to-catch-java-lang-error)

    我一般将 Error 看作是系统崩坏。
    比如某个接口抛出了 Exception ,我可能还 catch 一下,打个日志,返回个错误信息,至少其它接口还能用。
    而如果捕获到一个 Error ,我认为 jvm 就不可靠了,直接挂了吧。
    aguesuka
        11
    aguesuka  
       2022-07-18 19:41:54 +08:00   ❤️ 1
    @dcsuibian 可以用 uncheckedioexception, 语义比 RuntimeException 好
    zed1018
        12
    zed1018  
       2022-07-18 20:51:34 +08:00
    @matepi 在我组,我是明令禁止非必要抓 throwable 的,如果不能枚举足够的异常,那就是设计上根本就有问题。瞎抓不可取,该 crash 的一定要 crash 减少影响面
    yeqizhang
        13
    yeqizhang  
       2022-07-18 21:26:35 +08:00 via Android
    v 站大佬多呀,提的问题也都很好,今天又学习到了
    ychost
        14
    ychost  
       2022-07-18 22:27:56 +08:00
    @SneakThrows 用这个注解
    blankmiss
        15
    blankmiss  
       2022-07-18 22:56:50 +08:00
    @ychost 这个注解好像是为了骗过编译器来着
    ErnestSu
        16
    ErnestSu  
       2022-07-19 09:28:47 +08:00
    @zed1018
    在我组,我是明令禁止非必要抓 throwable 的,如果不能枚举足够的异常,那就是设计上根本就有问题。瞎抓不可取,该 crash 的一定要 crash 减少影响面
    ---------------------
    调用定制系统的 api ,不一定所有版本有这个实现,所有定制系统的 api ,我都会 catch Throwable
    nothingistrue
        17
    nothingistrue  
       2022-07-19 09:29:27 +08:00
    try (InputStream input = new FileInputStream("src/readme.txt")) {

    }catch (IOException e){

    }

    这才是正确的用法,因为 try-with-resources 只是自动调用 close (以及将 finally 当中抛出的异常转移到 try 当中抛出), 但不隐藏异常,对于 IOException 这种受检异常,你必须自己处理。
    nothingistrue
        18
    nothingistrue  
       2022-07-19 09:32:01 +08:00
    @zed1018
    @ErnestSu
    重点不是是否 catch ,是 catch 之后不能即不处理又不 throw 。
    shily
        19
    shily  
       2022-07-19 18:53:08 +08:00 via iPhone
    kotlin 解君愁
    night98
        20
    night98  
       2022-07-19 21:05:10 +08:00
    try with resource 的功能是自动关闭流,和异常捕获没有半毛钱关系,在 Java 中受检异常是必须要被处理的,嫌麻烦直接用 hutool 的文件工具类
    ychost
        21
    ychost  
       2022-07-19 22:31:33 +08:00
    @blankmiss 这个原理是改了你的代码,自动加了 try/catch 并抛了一个 RuntimeException
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5365 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 02:52 · PVG 10:52 · LAX 18:52 · JFK 21:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.