在大学项目开发中, 你有没发现自己做的项目总是出现 bug, 不仅仅出现 bug, 而且很难根据异常信息找到异常源. 我当时也是非常懊恼, 可怕的是不知道怎么维护... 软件 Java 异常需要理解基础的知识, 在实战中较好的处理异常. Java 异常基础知识 ,tryCatchFinally 语句块 本节总结 Java 异常在实践中的相关事项
1, 在 Finally 中清理资源或者使用 Try-With-Resource 语句
不要在 try 中关闭资源, 因为一旦发生异常, 将无法正常关闭资源. 以下代码给出二种处理方案, Finally 关闭资源, Try-With-Resource(JDK1.7 出现)
- /** 写数据
- * */
- public static void writeFile(File file) {
- OutputStream os=null;
- try {
- os=new FileOutputStream(file);
- String str=new String("hello gay!");
- // os.write(str); 不编码 -- 错误
- os.write(str.getBytes());// 按照默认的 GBK 编码
- os.write(5);
- os.flush();
- } catch (Exception e) {
- e.printStackTrace();
- }finally{
- try {
- os.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /** 写数据
- * */
- public static void writeFile(File file) {
- // 它将在 try 被执行后自动关闭, 或者处理一个异常.
- try(OutputStream os=new FileOutputStream(file)) {
- String str=new String("hello gay!");
- os.write(str.getBytes());// 按照默认的 GBK 编码
- os.write(5);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
2, 给出准确的异常处理信息
尽量能更好地描述你的异常处理信息, 比如用 NumberFormatException 代替 IllegalArgumentException , 避免抛出一个不具体的异常. catch 语句块中子类在前, 父类在后.
- public void doNotDoThis() throws Exception {
- }
- public void doThis() throws NumberFormatException {
- }
3, 记录自定义异常
为了给调用人员和维护者更清晰的异常信息, 请确保在 Javadoc 中添加一个 @throws 声明, 并描述可能导致的异常情况
- /**
- * This method does something extremely useful ...
- * @throws MyBusinessException if ... happens
- */
- public void doSome() throws MyBusinessException {
- ...
- }
4, 记录异常信息
用 1-2 个简短的句子解释异常的原因, 使用日志文件记录
- try {
- new Long("abc");
- } catch (NumberFormatException e) {
- log.error(new Exception("xxx",e));
- }
5, 最先捕获特定的异常
把特点的, 已知的异常先捕获. catch 块中只有第一个匹配到异常的 catch 语句才会被执行, 所以, 如果你最先发现 IllegalArgumentException, 你将永远不会到达 catch 里处理更具体的 NumberFormatException, 因为它是 IllegalArgumentException 的一个子类. 所以要首先捕获特定的异常类, 并在末尾添加一些处理不是很具体异常的 catch 语句. 子类应该在前面, 父类在后面. 最后一个 catch 可以写 Exception.
- public void catchMostSpecificExceptionFirst() {
- try {
- doSomething("A message");
- } catch (NumberFormatException e) {
- log.error(e);
- } catch (IllegalArgumentException e) {
- log.error(e)
- } catch(Exception){
- // 使用 Exception 捕获不确定的, 模糊的异常
- log.error(e);
- }
- }
6. 不要在 catch 中使用 Throwable
因为所有的 Exception(包括 Error) 都是 Throwtable 的子类. Error 是 JVM 异常, 我们无法预计和修改. Throwable 也不够仔细.
- public void doNotCatchThrowable() {
- try {
- // do something
- } catch (Throwable t) {
- // don't do this!
- }
- }
7, 不要捕获和抛出异常
或许这样看起来很 nice, 当它发生时记录一个异常, 然后重新抛出它, 以便调用者能够适当地处理它. 但是这样会同时打印日志信息和异常信息.
如果你需要添加额外的信息, 应该捕获异常并将其包装在一个自定义的信息中. 但要确保遵循下面的第 8 条异常链化.
- try {
- new Long("xyz");
- } catch (NumberFormatException e) {
- log.error(e);
- throw e;
- }
- 17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"
- Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"
- at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
- at java.lang.Long.parseLong(Long.java:589)
- at java.lang.Long.(Long.java:965)
- at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
- at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)
可能这样说不太清楚, 举个例子假如 main 调用 B 函数, 在 B 中调用 A 函数, A 中发生异常, 而我们把异常交给调用者处理 (main 中); 应该这样: A 中抛出异常, B 链化抛出, main 中捕获并且处理, 记录.
- public static void main(String[] args)
- {
- System.out.println("请输入 2 个加数");
- int result;
- try
- {
- result = add();
- System.out.println("结果:"+result);
- } catch (Exception e){
- //1, 记录
- log.error(e);
- //2, 处理, 比如打印;
- e.printStackTrace();
- }
- }
- // 获取输入的 2 个整数返回
- private static List<Integer> getInputNumbers()
- {
- List<Integer> nums = new ArrayList<>();
- Scanner scan = new Scanner(System.in);
- try {
- int num1 = scan.nextInt();
- int num2 = scan.nextInt();
- nums.add(new Integer(num1));
- nums.add(new Integer(num2));
- }catch(InputMismatchException immExp){
- throw immExp;
- }finally {
- scan.close();
- }
- return nums;
- }
- // 执行加法计算
- private static int add() throws Exception
- {
- int result;
- try {
- List<Integer> nums =getInputNumbers();
- result = nums.get(0) + nums.get(1);
- }catch(InputMismatchException immExp){
- throw new Exception("计算失败",immExp); ///////////////////////////// 链化: 以一个异常对象为参数构造新的异常对象.
- }
- return result;
- }
8 , 链化 -- 包装异常
异常的链化可以将多个模块的异常串联起来, 使得异常信息不会丢失.
异常链化: 以一个异常对象为参数构造新的异常对象. 新的异对象将包含先前异常的信息. 这项技术主要是异常类的一个带 Throwable 参数的函数来实现的. 这个当做参数的异常, 我们叫他根源异常 (cause).
- public static void main(String[] args)
- {
- System.out.println("请输入 2 个加数");
- int result;
- try
- {
- result = add();
- System.out.println("结果:"+result);
- } catch (Exception e){
- e.printStackTrace();
- }
- }
- // 获取输入的 2 个整数返回
- private static List<Integer> getInputNumbers()
- {
- List<Integer> nums = new ArrayList<>();
- Scanner scan = new Scanner(System.in);
- try {
- int num1 = scan.nextInt();
- int num2 = scan.nextInt();
- nums.add(new Integer(num1));
- nums.add(new Integer(num2));
- }catch(InputMismatchException immExp){
- throw immExp;
- }finally {
- scan.close();
- }
- return nums;
- }
- // 执行加法计算
- private static int add() throws Exception
- {
- int result;
- try {
- List<Integer> nums =getInputNumbers();
- result = nums.get(0) + nums.get(1);
- }catch(InputMismatchException immExp){
- throw new Exception("计算失败",immExp); ///////////////////////////// 链化: 以一个异常对象为参数构造新的异常对象.
- }
- return result;
- }
- /*
- 请输入 2 个加数
- r 1
- java.lang.Exception: 计算失败
- at practise.ExceptionTest.add(ExceptionTest.java:53)
- at practise.ExceptionTest.main(ExceptionTest.java:18)
- Caused by: java.util.InputMismatchException
- at java.util.Scanner.throwFor(Scanner.java:864)
- at java.util.Scanner.next(Scanner.java:1485)
- at java.util.Scanner.nextInt(Scanner.java:2117)
- at java.util.Scanner.nextInt(Scanner.java:2076)
- at practise.ExceptionTest.getInputNumbers(ExceptionTest.java:30)
- at practise.ExceptionTest.add(ExceptionTest.java:48)
- ... 1 more
- */
附加: finally 块的细节
不要在 fianlly 中使用 return.
不要在 finally 中抛出异常.
减轻 finally 的任务, 不要在 finally 中做一些其它的事情, finally 块仅仅用来释放资源是最合适的.
将尽量将所有的 return 写在函数的最后面, 而不是 try ... catch ... finally 中.
来源: https://www.cnblogs.com/achievement-active/p/9310975.html