博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

Posted on 2020-04-08 08:27  冲杀  阅读(632)  评论(3编辑  收藏  举报

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