【0】README

0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java异常—— finally 子句+带资源的 try语句 的相关知识;


【1】 finally 子句相关

1.1)产生资源回收问题:当代码抛出一个异常时, 就会终止方法中剩余代码的处理, 并退出这个方法的执行。如果方法获得了一些本地资源,且只有这个方法知道, 那么就会产生资源回收问题;
1.2)解决方法:

  • 1.2.1)一种解决方法是 捕获并重新抛出所有异常: 但是, 这种方法比较乏味, 因为需要在两个地方取出所有分配的资源;
  • 1.2.2)一种更好的解决方法是 finally 子句;

1.3)看个荔枝(不管是否异常被捕获, finally子句都会被执行),在下面的示例中, 程序将在所有cases 下关闭文件:

InputStream in = new FileIinputStream();
try
{
//1
code that might throw exceptions
//2
}
catch(IOException e)
{
//3
show error msg
//4
}
finally
{// 5in.close();
}
//6

对以上代码的分析(Analysis)(在上面的 代码中, 有下列3种cases 会执行finally 子句):

  • A1)代码没有抛出异常。在这种情况下, 程序首先执行try语句块中的全部代码, 然后执行 finally子句中的代码。随后执行try语句块之后的 第一条语句, 执行顺序为1、2、5、6;

  • A2)抛出一个在catch 子句中捕获的异常。

    • A2.1)如果catch子句没有抛出异常, 程序将执行try 语句块之后的第一条语句, 在这里的执行顺序为 1、3、4、5、6;
    • A2.2)如果catch 子句抛出异常, 异常将被抛出这个方法的调用者, 在这里, 执行顺序为 1、3、5;
  • A3)代码抛出了一个异常, 但catch 子句无法捕获; 在这里, 执行顺序为 1、5;

1.4)try语句可以只有 finally子句,而没有catch子句:如,

InputStream in = "...";
try
{}
finally
{in.close();
}
  • 1.4.1)无论在try 语句块中是否遇到异常,finally子句中的 in.close() 语句都会被执行, 当然, 如果真的遇到一个异常, 这个异常将会被重新抛出, 并且必须由另一个catch 子句捕获;
  • 1.4.2)我们在需要关闭资源的时候, 用这种方式使用 finally 子句是一个不错 的选择;

Hint)这里, 强烈建议独立使用 try/catch 和 try/finally 语句块, 可以提高代码的清晰度。如,(强烈推荐-strongly recommended)

InputStream in = "...";
try
{try{code that might throw exceptions}    finaly{in.close();}
}
catch(IOException e)
{show error msg
}
  • H1)内层的try语句块有一个职责, 就是确保关闭输入流;
  • H2)外层的try 语句块也只有一个职责, 就是确保报告出现的错误;
  • H3)这种设计不仅清楚, 而且还将报告finally子句中出现的错误;

Warning)

  • W1)当finally子句包含 return 语句时, 将会出现一种意想不到的结果;
  • W2)假设利用return 语句从try 语句块中退出。 在这个方法返回前, finally子句的内容将被执行;

1.5)如果finally子句也有一个 return, 这个返回值将会覆盖原始的返回, 看个荔枝

public static int f(int n)
{try{int r = n * n;return r;}finally{if(n==2) return 0;}
}

对上述代码的分析(Analysis):如果调用 f(2),那么try语句块return 4, 而方法返回前, 还要执行 finally子句, 其返回0, 这个返回值会覆盖掉原始的返回值4**(即最终的返回值是0 而不是4);**

1.6)出现的问题:

InputStream in = "...";
try
{code that might throw exceptions
}
finally
{in.close();
}
  • 1.6.1)问题描述:对于上述代码, 假设在 try 语句块中的代码抛出了 IOException异常, 这些异常只有这个方法的调用者才能够处理。 执行finally语句块, 并调用close 方法。 而 close 方法本身也可能抛出 IOException异常。 当出现这种case 时, 原始的异常数据将丢失, 转而抛出 close 方法的异常;
  • 1.6.2)解决方法: 如果你想做适当处理的话, 重新抛出原来的异常,代码会变得极其繁琐;如下图所示:
InputStream in = "...";
Exception ex = null;
try
{try{code that might throw exceptions}        catch(Exception e){ex = e;throw e;}
}
finaly
{try{in.close();}catch(Exception e){if(ex == null) throw e;}
}    

【2】 带资源的 try语句

2.1)对于以下代码模式:

open a resource
try
{work with the resource
}
finally
{close the resource
}
  • 2.1.1)假设资源属于一个实现了 AutoCloseable 接口的类, AutoCloseable 接口有一个方法:
void close()  throws Exception;

Annotation)还有一个 Closeable 接口, 它是 AutoCloseable 的子接口, 也包含一个 close方法, 不过, 这个方法声明为抛出一个 IOException;
2.2)带资源的 try语句(try-with-resource)的最简单形式为:

try(Resource res)
{work with  res
}
  • 2.2.1)try块退出时, 会自动调用 res.close()。看个荔枝——读取一个文件中的所有单词:
try(Scanner in = new Scanner(new FileInputStream("/usr/.../")))
{while(in.hasNext())System.out.println(in.next());
}
  • 上述代码中的 try块正常退出时, 或者存在一个异常时, 都会调用 in.close()方法, 就好像使用了 finally块一样;
  • 2.2.2)还可以指定多个 资源:
try(Scanner in = new Scanner(new FileInputStream("/usr/.../")), PrintWriter out = new PrintWriter("out.txt"))
{while(in.hasNext())out.println(in.next().toUpperCase());
}
  • 2.2.3)无论这个块如何退出, in 和 out 都会关闭: 如果你使用常规方式手动编程,就需要两个嵌套的 try/finally 子句;

Conclusion)

  • C1)我们看到, 如果try块中抛出一个异常, 而且close方法也抛出一个异常, 这就会带来一个难题, 现在 带资源的try块解决了这个问题;
  • C2)原来的异常会被重新抛出, 而 close方法抛出的异常会“被抑制”;
  • C3)这些异常将自动捕获, 并由 addSuppressed 方法增加到原来的异常。如果对异常有兴趣, 可以调用 getSuppressed 方法, 它会得到从 close方法 抛出并被抑制的异常列表;

Attention)只要需要关闭资源, 就要尽可能地使用带资源的 try语句;

java异常—— finally 子句+带资源的 try语句相关推荐

  1. Java 1.3.1 带标签的 break语句

    与 C++ 不同,Java 还提供了一种带标签的 break语句,用于跳出多重嵌套的循环语句. 标签必须放在希望跳出的最外 层循环之前, 并且必须紧跟一个冒号. Scanner in = new Sc ...

  2. Java基础—break label 带标签的break语句的用法。

    是这样的,今天看RocketMQ的Client的时候,里面出现了一个写Java没有看到过的东西 - - 记录一下. 也是就是带标签的break: RocketMQ的Client中的使用 while(t ...

  3. JAVA//异常、断言和日志

    1. 处理错误 1.2 异常分类 异常对象都是派生于 Throwable 类的一个实例.用户可以创建自己的异常类. Error 类层次结构描述了 Java 运行时系统的内部错误和资源耗尽错误. 应用程 ...

  4. Java异常日志的查询语句_java学习异常,断言和日志

    1.异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器 2.错误分类 用户输入错误 设备错误 物理限制 代码错误 3.异常分类,所有的异常都是由Throwable继承而来,有 ...

  5. Java异常捕获论文_一篇文章解决Java异常处理

    前言 与异常相关的内容其实很早就想写了,但由于各种原因(懒)拖到了现在.在大二开学前夜(今天是8.31)完成这篇博客,也算完成了暑期生活的一个小心愿. 以下内容大多总结自<Java核心技术 卷Ⅰ ...

  6. java异常——分析堆栈跟踪元素+使用异常机制的技巧

    [0]README 0.1) 本文描述+源代码均 转自 core java volume 1, 旨在理解 java异常--分析堆栈跟踪元素+使用异常机制的技巧 的相关知识: [1]分析堆栈跟踪元素相关 ...

  7. Java异常-受查与非受查

    Java异常-受查与非受查 所有的异常都是由Throwable继承而来,下级分为Error和Exception Error Error表示Java运行时系统的内部错误和资源耗尽错误,不应该抛出该类型的 ...

  8. 我可以在同一个catch子句中捕获多个Java异常吗?

    本文翻译自:Can I catch multiple Java exceptions in the same catch clause? In Java, I want to do something ...

  9. java 异常 抛 效率_一文带你理清Java异常体系,提高开发效率

    一.概述 我们在项目开发的过程中使用异常是必不可少的事情,那么异常会带来哪些好处呢? 我们知道异常带来的最明显的好处是,它能够降低错误处理代码的复杂度.不使用异常的话,我们就必须检查一些特定的错误,并 ...

最新文章

  1. 201671010128 2017-09-17《Java程序设计》之步步深入面向对象
  2. java 接口与抽象类的区别
  3. 用python编写的无线AP扫描器
  4. PHP和OneNet平台交互
  5. h5微信本地调试 vue_Vue 移动端微信内H5调起支付(利用js sdk)
  6. 老男孩教育50期左婷婷-day03-xhell连接服务器-远程连接排错-基础命令
  7. struts基础配置
  8. 12款免费素材图标系列三
  9. DCIC巡游车与网约车运营特征对比分析-数据读取
  10. matlab创建nc文件怎么打开,MATLAB打开nc文件并读取nc文件数据
  11. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)...
  12. oracle怎么分配表空间,oracle数据库分配表空间、创造用户、分配用户权限操作
  13. 英语4级口语是计算机评分吗,2017年11月英语四级口语评分标准
  14. Top20網頁爬蟲工具—5分鐘獲取網站數據
  15. allennlp 版本关系
  16. 四川师范大学地信概论(3- 空间数据模型)90分以上版本
  17. 音频变压器阻抗匹配及案例
  18. 《人月神话》7(The Mythical Man-Month)为什么巴比伦塔会失败?
  19. 使用微信公众号发送模板消息
  20. C语言中scanf()函数中的是什么

热门文章

  1. P3206 [HNOI2010]城市建设
  2. CF1548B Integers Have Friends
  3. Three Bags CodeForces - 1467C
  4. [NOI Online 2022 提高组] 丹钓战(单调栈 + 树状数组 / 主席树)
  5. 【学习笔记】浅谈短小可爱的左偏树(可并堆)
  6. CF891B-Gluttony【构造】
  7. P3980-[NOI2008]志愿者招募【费用流】
  8. P4331-[BalticOI2004]Sequence数字序列【左偏树】
  9. codeforces F.Fibonacci String Subsequences
  10. 38、JAVA_WEB开发基础之下载功能