1. 程式人生 > >無聊系列 - 教你怎麼正確處理異常

無聊系列 - 教你怎麼正確處理異常

在工作中,常遇見亂處理Exception的情況:

  1. 要麼吞掉異常,不列印任何日誌;
  2. 要麼記錄日誌時,日誌級別不對、或者把重要的出錯堆疊資訊幹掉,在做生產問題排查時,簡直讓人抓狂。

我這篇博文,也是對記錄的一個開源元件,對異常自行K掉,造成我排查耗費了好久的時間--。https://www.cnblogs.com/chongsha/p/11931109.html

下面我們用一段程式碼對1進行舉例,該程式碼是網上隨便搜的,原作者請勿見怪。

 1  /*
 2    * 加密
 3    * 1.構造金鑰生成器
 4    * 2.根據ecnodeRules規則初始化金鑰生成器
 5    * 3.產生金鑰
 6    * 4.建立和初始化密碼器
 7    * 5.內容加密
 8    * 6.返回字串
 9    */
10     public static String AESEncode(String encodeRules,String content){
11         try {
12             //1.構造金鑰生成器,指定為AES演算法,不區分大小寫
13             KeyGenerator keygen=KeyGenerator.getInstance("AES");
14             //2.根據ecnodeRules規則初始化金鑰生成器
15             //生成一個128位的隨機源,根據傳入的位元組陣列
16             keygen.init(128, new SecureRandom(encodeRules.getBytes()));
17               //3.產生原始對稱金鑰
18             SecretKey original_key=keygen.generateKey();
19               //4.獲得原始對稱金鑰的位元組陣列
20             byte [] raw=original_key.getEncoded();
21             //5.根據位元組陣列生成AES金鑰
22             SecretKey key=new SecretKeySpec(raw, "AES");
23               //6.根據指定演算法AES自成密碼器
24             Cipher cipher=Cipher.getInstance("AES");
25               //7.初始化密碼器,第一個引數為加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二個引數為使用的KEY
26             cipher.init(Cipher.ENCRYPT_MODE, key);
27             //8.獲取加密內容的位元組陣列(這裡要設定為utf-8)不然內容中如果有中文和英文混合中文就會解密為亂碼
28             byte [] byte_encode=content.getBytes("utf-8");
29             //9.根據密碼器的初始化方式--加密:將資料加密
30             byte [] byte_AES=cipher.doFinal(byte_encode);
31           //10.將加密後的資料轉換為字串
32             //這裡用Base64Encoder中會找不到包
33             //解決辦法:
34             //在專案的Build path中先移除JRE System Library,再新增庫JRE System Library,重新編譯後就一切正常了。
35             String AES_encode=new String(new BASE64Encoder().encode(byte_AES));
36           //11.將字串返回
37             return AES_encode;
38         } catch (NoSuchAlgorithmException e) {
39             e.printStackTrace();
40         } catch (NoSuchPaddingException e) {
41             e.printStackTrace();
42         } catch (InvalidKeyException e) {
43             e.printStackTrace();
44         } catch (IllegalBlockSizeException e) {
45             e.printStackTrace();
46         } catch (BadPaddingException e) {
47             e.printStackTrace();
48         } catch (UnsupportedEncodingException e) {
49             e.printStackTrace();
50         }
51         
52         //如果有錯就返加nulll
53         return null;         
54     }

該段程式碼主要的問題是:

  1. 吃掉了異常,因為是公共類,連日誌記錄都沒有
  2. 出現異常後,仍然返回了一個null值。

這個方法在我們平時使用時,如果不讀原始碼,直接使用,第一直覺是,返回正確結果,如果不正確,那就會丟擲異常。但是這段程式碼卻返回了null,使用者遇到時,會抓狂,這是什麼情況啊,為啥不對,明明沒有報錯,萬般無奈,進程式碼一看。。。原來是把異常給幹掉了。

對此程式碼做出的改進建議是:

  1. 在方法上宣告throws是
  2. 如果你覺得1方案不爽,可以直接一個大的catch Exception,然後throw new RuntimeException(e.getMessage(), e);
  3. 出錯了就是出錯了,不能把錯誤自己幹掉,然後返回一個null。

要麼記錄日誌時,日誌級別不對、或者把重要的出錯堆疊資訊幹掉,在做生產問題排查時,簡直讓人抓狂。

在用log4j記錄日誌時,請正確使用logger.error()來記錄日誌,請注意該方法的過載,不要使用 Exception的getMessage()方法只記錄異常的訊息,而把異常的錯誤堆疊給拋棄,異常的錯誤堆疊是很有用的資訊,會告訴你在哪行程式碼出錯了,這樣你可以快速的定位錯誤。

 1 package com.demo;
 2 
 3 public class Test {
 4 
 5     public static void main(String[] args) {
 6         try {
 7             int a = 0;
 8             int b = 1;
 9 
10             System.out.println(b / a);
11         } catch (Exception e) {
12             e.printStackTrace();
13         }
14     }
15 
16 }

 

這段程式碼的錯誤堆疊資訊:

java.lang.ArithmeticException: / by zero
at com.demo.Test.main(Test.java:10)

這行錯誤資訊at com.demo.Test.main(Test.java:10)標明瞭出錯位置,可以快速定位是在什麼地方。所以在記錄日誌的時候,請不要把錯誤堆疊資訊幹掉了。