无聊系列 – 教你怎么正确处理异常

在工作中,常遇见乱处理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)标明了出错位置,可以快速定位是在什么地方。所以在记录日志的时候,请不要把错误堆栈信息干掉了。