Java优化(二) 异常处理


在这里插入图片描述

1、不要使用printStackTrace()

  • 反例:
        try {
            int i =1/0;
        } catch (Exception e) {
            e.printStackTrace();
        }
  • 正例:
        try {
            int i =1/0;
        } catch (Exception e) {
            logger.error("异常信息:{}",e);
        }

注意!!!

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

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

  • 反例:
public void test(){
    try{
        //…抛出 IOException 的代码调用
        //…抛出 SQLException 的代码调用
    }catch(Exception e){
        //用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息哦
        logger.error(Exception in test,exception:{}, e);
    }
}
  • 正例:
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块中吃掉异常

  • 反例:
        try {
            int i =1/0;
        } catch (Exception e) {
            logger.error("异常信息");
        }
  • 正例:
        try {
            int i =1/0;
        } catch (Exception e) {
            logger.error("异常信息:{}",e);
        }

注意!!!

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

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

  • 反例:
        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关闭流资源:
        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来处理:
        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、捕获异常与抛出异常必须是完全匹配,或者捕获异常是抛异常的父类

  • 反例:
//BizException 是 Exception 的子类
public class BizException extends Exception {}
//抛出父类Exception
public static void test() throws Exception {}

try {
	//编译错误
    test(); 
    //捕获异常子类是没法匹配
} catch (BizException e) { 
    log.error(e);
}
  • 正例:
//抛出子类Exception
public static void test() throws BizException {}

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

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

  • 反例:
public static void testIgnoreException() throws Exception {
    try {       
       int i =1/0;
    } catch (Exception e) {
        
    }
}
  • 正例 :
public static void testIgnoreException() throws Exception {
    try {       
       int i =1/0;
    } catch (Exception e) {
       logger.error("异常信息:{}",e);
    }
}

注意!!!

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

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

  • 反例:
public UserInfo queryUserInfoByUserId(Long userid) throw SQLException {
    //根据用户Id查询数据库
}

  • 正例 :
public UserInfo queryUserInfoByUserId(Long userid) {
    try{
        //根据用户Id查询数据库
    }catch(SQLException e){
        log.error("查询数据库异常啦,{}",e);
    }finally{
        //关闭连接,清理资源
    }
}

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

  • 反例:
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);
    }


  • 正例 :

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 的方式来处理

  • 反例:
try {
  obj.method() 
} catch (NullPointerException e) {
...
}

  • 正例 :
if (obj != null){
   ...
}

10、优先捕获具体的异常

  • 注意异常的匹配顺序,因为只有第一个匹配到异常的catch块才会被执行。如果你希望看到,是NumberFormatException异常,就抛出NumberFormatException,如果是IllegalArgumentException就抛出IllegalArgumentException。
  • 反例:
try {
    doSomething("test exception");
} catch (IllegalArgumentException e) {       
    log.error(e);
} catch (NumberFormatException e) {
    log.error(e);
}

  • 正例 :
try {
    doSomething("test exception");
} catch (NumberFormatException e) {       
    log.error(e);
} catch (IllegalArgumentException e) {
    log.error(e);
}

注意!!!

  • 因为NumberFormatException是IllegalArgumentException 的子类,反例中,不管是哪个异常,都会匹配到IllegalArgumentException,就不会再往下执行啦,因此不知道是否是NumberFormatException。所以需要优先捕获具体的异常,把NumberFormatException放前面。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值