java异常处理的十个建议(代码片段)

jay-huaxiao jay-huaxiao     2022-11-30     261

关键词:

前言

Java异常处理的十个建议,希望对大家有帮助~

本文已上传github:

https://github.com/whx123/JavaHome

公众号:捡田螺的小男孩

一、尽量不要使用e.printStackTrace(),而是使用log打印。

反例:

try
  // do what you want  
catch(Exception e)
  e.printStackTrace();

正例:

try
  // do what you want  
catch(Exception e)
  log.info("你的程序有异常啦,",e);

理由:

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

二、catch了异常,但是没有打印出具体的exception,无法更好定位问题

反例:

try
  // do what you want  
catch(Exception e)
  log.info("你的程序有异常啦");

正例:

try
  // do what you want  
catch(Exception e)
  log.info("你的程序有异常啦,",e);

理由:

  • 反例中,并没有把exception出来,到时候排查问题就不好查了啦,到底是SQl写错的异常还是IO异常,还是其他呢?所以应该把exception打印到日志中哦~

三、不要用一个Exception捕捉所有可能的异常

反例:

public void test()
    try
        //…抛出 IOException 的代码调用
        //…抛出 SQLException 的代码调用
    catch(Exception e)
        //用基类 Exception 捕捉的所有可能的异常,如果多个层次都这样捕捉,会丢失原始异常的有效信息哦
        log.info(“Exception in test,exception:”, e);
    

正例:

public void test()
    try
        //…抛出 IOException 的代码调用
        //…抛出 SQLException 的代码调用
    catch(IOException e)
        //仅仅捕捉 IOException
        log.info(“IOException in test,exception:”, e);
    catch(SQLException e)
        //仅仅捕捉 SQLException
        log.info(“SQLException in test,exception:”, e);
    

理由:

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

四、记得使用finally关闭流资源或者直接使用try-with-resource

反例:

FileInputStream fdIn = null;
try 
    fdIn = new FileInputStream(new File("/jay.txt"));
    //在这里关闭流资源?有没有问题呢?如果发生异常了呢?
    fdIn.close();
 catch (FileNotFoundException e) 
    log.error(e);
 catch (IOException e) 
    log.error(e);

正例1:

需要使用finally关闭流资源,如下

FileInputStream fdIn = null;
try 
    fdIn = new FileInputStream(new File("/jay.txt"));
 catch (FileNotFoundException e) 
    log.error(e);
 catch (IOException e) 
    log.error(e);
finally 
    try 
        if (fdIn != null) 
            fdIn.close();
        
     catch (IOException e) 
        log.error(e);
    

正例2:

当然,也可以使用JDK7的新特性try-with-resource来处理,它是Java7提供的一个新功能,它用于自动资源管理。

  • 资源是指在程序用完了之后必须要关闭的对象。
  • try-with-resources保证了每个声明了的资源在语句结束的时候会被关闭
  • 什么样的对象才能当做资源使用呢?只要实现了java.lang.AutoCloseable接口或者java.io.Closeable接口的对象,都OK。
try (FileInputStream inputStream = new FileInputStream(new File("jay.txt")) 
    // use resources   
 catch (FileNotFoundException e) 
    log.error(e);
 catch (IOException e) 
    log.error(e);

理由:

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

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

反例:

//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);

六、捕获到的异常,不能忽略它,至少打点日志吧

反例:

public static void testIgnoreException() throws Exception 
    try        
        // 搞事情
     catch (Exception e)      //一般不会有这个异常
        
    

正例:

public static void testIgnoreException() 
    try 
        // 搞事情
     catch (Exception e)      //一般不会有这个异常
        log.error("这个异常不应该在这里出现的,",e); 
    

理由:

  • 虽然一个正常情况都不会发生的异常,但是如果你捕获到它,就不要忽略呀,至少打个日志吧~

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

反例:

public UserInfo queryUserInfoByUserId(Long userid) throw SQLException 
    //根据用户Id查询数据库

正例:

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

理由:

  • 我们的项目,一般都会把代码分 Action、Service、Dao 等不同的层次结构,如果你是DAO层处理的异常,尽早处理吧,如果往上 throw SQLException,上层代码就还是要try catch处理啦,这就污染了你的代码~

八、自定义封装异常,不要丢弃原始异常的信息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);
    

运行结果如下,没有了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("文件在哪里呢", 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);
    

技术图片

九、运行时异常RuntimeException ,不应该通过catch 的方式来处理,而是先预检查,比如:NullPointerException处理

反例:

try 
  obj.method() 
 catch (NullPointerException e) 
...

正例:

if (obj != null)
   ...

十、注意异常匹配的顺序,优先捕获具体的异常

注意异常的匹配顺序,因为只有第一个匹配到异常的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放前面~

公众号

技术图片

  • 欢迎关注我个人公众号,交个朋友,一起学习哈~
  • 如果答案整理有错,欢迎指出哈,感激不尽~

在java中记录日志的十个小建议(代码片段)

JAVA日志管理既是一门科学,又是一门艺术。科学的部分是指了解写日志的工具以及其API,而选择日志的格式,消息的格式,日志记录的内容,哪种消息对应于哪一种日志级别,则完全是基于经验。从过去的实践证明,JAVA的日志... 查看详情

预处理器less的十个语法(代码片段)

Less是一门CSS预处理语言,它扩充了CSS语言,增加了诸如变量、混合(mixin)、函数等功能,让CSS更易维护、方便制作主题、扩充。不过浏览器只能识别CSS语言,所以Less语言直接运行在浏览器端是不被识别... 查看详情

网页搜索(百度谷歌)你不得不知道的十个小技巧(代码片段)

网页搜索(百度谷歌)你不得不知道的十个小技巧百度搜索广告多,谷歌搜索搜不到东西,这时候,你得问问自己——你,用对姿势了么?文章目录网页搜索(百度谷歌)你不得不知道的十个小... 查看详情

java常用的十个框架

...按模型数据和它生成的HTML输出,controller(控制器)负责处理用户的请求并且建立适当的模型,并且把它传递给视图渲染spring的web模型-视图-控制器(MVC)框架是围绕着处理所有HTTP请求和响应DispatcherServlet的设计。具体步骤:1.用... 查看详情

值得收藏面试会用到的十个常用的数组方法js实现(代码片段)

【手撕代码系列】之十个常用的数组方法JS实现(一)🚀通俗易懂的实现方式,帮助我们认识相应的方法📚收藏本系列,基础进阶两不误🎉本系列持续更新,欢迎查看线上地址写在前面代码实现系... 查看详情

2020年精心收集的十个java开发网站

不管谁手里都藏着些许自己觉得好用的网站,今天专门找大厂出来的同学同事觉得好用的网站分享给大家,如果这里有你没收藏还不知道觉得还蛮有用的网站可以给我点个赞,大家一起进步,一起学习,同时也可以分享你觉得好... 查看详情

值得收藏面试会用到的十个常用的数组方法js实现(代码片段)

...最后剩余的元素将组成一个区块。1.1参数array(Array):需要处理的数组[size=1](number):每个数组区块的长度1.2返回(Array):返回一个包含拆分区块的新数组(注:相当于一个二维数组)。1.3实现const_chunk=function(array,size=... 查看详情

java异常使用(代码片段)

Java异常就是Java对程序运行时错误的处理。Java的所有异常都继承自java.lang.Throwable类。Java的异常处理框架如下:在《EffectIveJava》(高效的Java)一书中关于异常有几点建议:1、只针对异常的情况才使用异常2、对可... 查看详情

程序员最关心的十个问题,我帮你问了chatgpt

...地步。尽管AI可以自动生成一些简单的代码,但是在处理复杂的代码时,它仍然 查看详情

java程序的151个建议-提倡异常封装,采用异常链传递异常(代码片段)

Java语言的异常处理机制可以确保程序的健壮性,提高系统的可用率,但是JavaAPI提供的异常都是比较低级的(这里的低级是指“低级别”的异常),只有开发人员才能看得懂,才明白发生了什么问题。而对... 查看详情

java程序的151个建议-提倡异常封装,采用异常链传递异常(代码片段)

Java语言的异常处理机制可以确保程序的健壮性,提高系统的可用率,但是JavaAPI提供的异常都是比较低级的(这里的低级是指“低级别”的异常),只有开发人员才能看得懂,才明白发生了什么问题。而对... 查看详情

你不知道的前端异常处理(万字长文,建议收藏)(代码片段)

除了调试,处理异常或许是程序员编程时间占比最高的了。我们天天和各种异常打交道,就好像我们天天和Bug打交道一样。因此正确认识异常,并作出合适的异常处理就显得很重要了。我们先尝试抛开前端这个限定条... 查看详情

dart学习--dart之异常处理(代码片段)

  概述:    Dart2的异常与Java是非常类似的。Dart2的异常是Exception或者Error(包括它们的子类)的类型,甚至可以是非Exception或者Error类,也可以抛出,但是不建议这么使用。  Exception主要是程序本身可以处理的异常,比... 查看详情

级数的十个重要公式

查看详情

从jdk8到jdk18,java垃圾回收的十次进化(代码片段)

作者|ThomasSchatzl译者|弯月出品|CSDN(ID:CSDNnews)经历了数千次改进,Java的垃圾回收在吞吐量、延迟和内存大小方面有了巨大的进步。2014年3月JDK8发布,自那以来JDK又连续发布了许多版本,直到今日的JDK18是... 查看详情

2019年成为更好的java开发者的十个提示

我经常收到读者发来的电子邮件,要求我告诉他们如何成为更好的Java开发人员,他们应该学习什么,以及他们可以成为RockstarJava开发人员的工作领域和方向有哪些?在过去几年中单独回答之后,我想了几点... 查看详情

耗时一周深入理解jvm虚拟机异常处理字节码性能优化,全网最全面的jvm原理通俗易懂(强烈建议收藏)(代码片段)

...器垃圾收集堆永恒的数学:JVM模拟Java虚拟机如何处理异常例外JVM怎么处理字节码字节码格式原始类型将常量压入堆栈将局部变量压入堆栈弹出到局部变量类型转换转换转移ÿ 查看详情

java异常处理(代码片段)

查看详情