目录

1、不要使用printStackTrace() 2、不要用一个Exception捕捉所有异常 3、不要在catch块中吃掉异常 4、使用finally或者try-with-resource,关闭流资源 5、捕获异常与抛出异常必须是完全匹配,或者捕获异常是抛异常的父类 6、捕获到的异常,不能忽略 7、注意异常对你的代码层次结构的侵染(早发现早处理) 8、自定义封装异常,不要丢弃原始异常的信息Throwable cause 9、 先预检查运行时异常RuntimeException,不应该通过catch 的方式来处理 10、优先捕获具体的异常


![在这里插入图片描述](https://img-blog.csdnimg.cn/b6fe102366604b91930b65356c396ea9.png)

1、不要使用printStackTrace()

反例:

text
1 2 3 4 5 6
      try {
         int i =1/0;
      } catch (Exception e) {
         e.printStackTrace();
      }

正例:

text
1 2 3 4 5 6
      try {
         int i =1/0;
      } catch (Exception e) {
         logger.error("异常信息:{}",e);
      }

注意!!!

printStackTrace()打印出的堆栈日志跟业务代码日志是交错混合在一起的,通常排查异常日志不太方便。 e.printStackTrace()语句产生的字符串记录的是堆栈信息,如果信息太长太多,字符串常量池所在的内存块没有空间了,即内存满了,那么,用户的请求就被卡住。

2、不要用一个Exception捕捉所有异常

反例:

text
1 2 3 4 5 6 7 8 9 10
public void test(){
   try{
      //…抛出 IOException 的代码调用
      //…抛出 SQLException 的代码调用
   }catch(Exception e){
      //用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息哦
      logger.error(“Exception in test,exception:{}”, e);
   }
}

正例:

text
1 2 3 4 5 6 7 8 9 10 11 12 13
public void test(){
   try{
      //…抛出 IOException 的代码调用
      //…抛出 SQLException 的代码调用
   }catch(IOException e){
      //仅仅捕捉 IOException
      logger.error(“IOException in test,exception:{}”, e);
   }catch(SQLException e){
      //仅仅捕捉 SQLException
      logger.error(“SQLException in test,exception:{}”, e);
   }
}

注意!!!

用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息

3、不要在catch块中吃掉异常

反例:

text
1 2 3 4 5 6
      try {
         int i =1/0;
      } catch (Exception e) {
         logger.error("异常信息");
      }

正例:

text
1 2 3 4 5 6
      try {
         int i =1/0;
      } catch (Exception e) {
         logger.error("异常信息:{}",e);
      }

注意!!!

没有把exception打印出来,这样异常就会被吞掉,无法获取到任何失败信息,会给日后的问题排查带来巨大困难。

4、使用finally或者try-with-resource,关闭流资源

反例:

text
1 2 3 4 5 6 7 8 9 10
      FileInputStream fileInputStream = null;
      try {
         fileInputStream = new FileInputStream(new File("/document.txt"));
         fileInputStream.close();
      } catch (FileNotFoundException e) {
         logger.error(e);
      } catch (IOException e) {
         logger.error(e);
      }

正例 1 使用finally关闭流资源:

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
      FileInputStream fileInputStream = null;
      try {
         fileInputStream = new FileInputStream(new File("/document.txt"));
      } catch (FileNotFoundException e) {
         logger.error(e);
      } catch (IOException e) {
         logger.error(e);
      }finally {
         try {
            if (fileInputStream != null) {
               fileInputStream.close();
            }
         } catch (IOException e) {
            logger.error(e);
         }
      }

正例 2 使用try-with-resource来处理:

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
      try (FileInputStream fis = new FileInputStream("D:\\小滴课堂\\a.txt");
          BufferedInputStream bis = new BufferedInputStream(fis);
          FileOutputStream fos = new FileOutputStream("D:\\小滴课堂\\b.txt");
          BufferedOutputStream bos = new BufferedOutputStream(fos);
      ) {
         int size;
         byte[] buf = new byte[1024];
         while ((size = bis.read(buf)) != -1) {
            bos.write(buf, 0, size);
         }
      } catch (Exception e) {
         logger.error(e);
      }
// 在try()里面定义多个资源,执行完成后会自动关闭,关闭顺序是最先关闭最后在try()中定义的资源。

注意!!!

如果不使用finally或者try-with-resource,当程序发生异常,IO资源流没关闭,那么这个IO资源就会被他一直占着,这样别人就没有办法用了,这就造成资源浪费。

5、捕获异常与抛出异常必须是完全匹配,或者捕获异常是抛异常的父类

反例:

text
1 2 3 4 5 6 7 8 9 10 11 12 13
//BizException 是 Exception 的子类
public class BizException extends Exception {}
//抛出父类Exception
public static void test() throws Exception {}

try {
    //编译错误
   test(); 
   //捕获异常子类是没法匹配
} catch (BizException e) { 
   log.error(e);
}

正例:

text
1 2 3 4 5 6 7 8 9
//抛出子类Exception
public static void test() throws BizException {}

try {
   test();
} catch (Exception e) {
   log.error(e);
}

6、捕获到的异常,不能忽略

反例:

text
1 2 3 4 5 6 7 8
public static void testIgnoreException() throws Exception {
   try {      
      int i =1/0;
   } catch (Exception e) {
      
   }
}

正例 :

text
1 2 3 4 5 6 7 8
public static void testIgnoreException() throws Exception {
   try {      
      int i =1/0;
   } catch (Exception e) {
      logger.error("异常信息:{}",e);
   }
}

注意!!!

虽然一个正常情况都不会发生的异常,但是如果你捕获到它,就不要忽略。

7、注意异常对你的代码层次结构的侵染(早发现早处理)

反例:

text
1 2 3 4 5
public UserInfo queryUserInfoByUserId(Long userid) throw SQLException {
   //根据用户Id查询数据库
}

正例 :

text
1 2 3 4 5 6 7 8 9 10 11
public UserInfo queryUserInfoByUserId(Long userid) {
   try{
      //根据用户Id查询数据库
   }catch(SQLException e){
      log.error("查询数据库异常啦,{}",e);
   }finally{
      //关闭连接,清理资源
   }
}

8、自定义封装异常,不要丢弃原始异常的信息Throwable cause

反例:

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
public class TestChainException {
   public void readFile() throws MyException{
      try {
         InputStream is = new FileInputStream("jay.txt");
         Scanner in = new Scanner(is);
         while (in.hasNext()) {
            System.out.println(in.next());
         }
      } catch (FileNotFoundException e) {
         //e 保存异常信息
         throw new MyException("文件在哪里呢");
      }
   }
   public void invokeReadFile() throws MyException{
      try {
         readFile();
      } catch (MyException e) {
         //e 保存异常信息
         throw new MyException("文件找不到");
      }
   }
   public static void main(String[] args) {
      TestChainException t = new TestChainException();
      try {
         t.invokeReadFile();
      } catch (MyException e) {
         e.printStackTrace();
      }
   }
}
//MyException 构造器
public MyException(String message) {
      super(message);
   }


正例 :

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37

public class TestChainException {
   public void readFile() throws MyException{
      try {
         InputStream is = new FileInputStream("jay.txt");
         Scanner in = new Scanner(is);
         while (in.hasNext()) {
            System.out.println(in.next());
         }
      } catch (FileNotFoundException e) {
         //e 保存异常信息
         throw new MyException("文件在哪里呢", e);
      }
   }
   public void invokeReadFile() throws MyException{
      try {
         readFile();
      } catch (MyException e) {
         //e 保存异常信息
         throw new MyException("文件找不到", e);
      }
   }
   public static void main(String[] args) {
      TestChainException t = new TestChainException();
      try {
         t.invokeReadFile();
      } catch (MyException e) {
         e.printStackTrace();
      }
   }
}
//MyException 构造器
public MyException(String message, Throwable cause) {
      super(message, cause);
   }

9、 先预检查运行时异常RuntimeException,不应该通过catch 的方式来处理

反例:

text
1 2 3 4 5 6 7
try {
  obj.method() 
} catch (NullPointerException e) {
...
}

正例 :

text
1 2 3 4 5
if (obj != null){
   ...
}

10、优先捕获具体的异常

注意异常的匹配顺序,因为只有第一个匹配到异常的catch块才会被执行。如果你希望看到,是NumberFormatException异常,就抛出NumberFormatException,如果是IllegalArgumentException就抛出IllegalArgumentException。 反例:

text
1 2 3 4 5 6 7 8 9
try {
   doSomething("test exception");
} catch (IllegalArgumentException e) {      
   log.error(e);
} catch (NumberFormatException e) {
   log.error(e);
}

正例 :

text
1 2 3 4 5 6 7 8 9
try {
   doSomething("test exception");
} catch (NumberFormatException e) {      
   log.error(e);
} catch (IllegalArgumentException e) {
   log.error(e);
}

注意!!!

因为NumberFormatException是IllegalArgumentException 的子类,反例中,不管是哪个异常,都会匹配到IllegalArgumentException,就不会再往下执行啦,因此不知道是否是NumberFormatException。所以需要优先捕获具体的异常,把NumberFormatException放前面。

原文地址:https://blog.csdn.net/dmjxsy/article/details/129664316?ops_request_misc=&request_id=&biz_id=&utm_medium=distribute.pc_search_result.none-task-blog-2~all~koosearch~default-11-129664316-null-null.142^v87^koosearch_v1,239^v2^insert_chatgpt&utm_term=java%E4%BC%98%E5%8C%96