微服务时代java异常捕捉

一、尽量不要使用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放前面~
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/58550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

L1-042 日期格式化(Python实现) 测试点全过

题目 世界上不同国家有不同的写日期的习惯。比如美国人习惯写成“月-日-年”,而中国人习惯写成“年-月-日”。下面请你写个程序,自动把读入的美国格式的日期改写成中国习惯的日期。 输入格式 输入在一行中按照“mm-dd-yyyy”的格式给出月、日、年。题目…

2023常见前端面试题

以下是一些2023年秋招常见的前端面试题及其答案: 1. 请解释一下什么是前端开发? 前端开发是指使用HTML、CSS和JavaScript等技术来构建网页和用户界面的过程。前端开发人员负责将设计师提供的视觉设计转化为可交互的网页,并确保网页在不同设备…

LNMT与动静分离 (四十八)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、LNMT 二、Nginx高级配置 2.1 location 2.2 rewirte 2.2.1 应用场景 2.2.2 书写位置 三、动静分离 总结 前言 LNMT是一个高级神经机器翻译系统,它使…

【Python进阶学习】【Excel读写】使用openpyxl写入xlsx文件

1、当前文件不存在指定的子文件夹则创建 2、文件存在追加写入 3、文件不存在创建文件并写入表头 # -*- coding: utf-8 -*- import openpyxl as xl import osdef write_excel_file(folder_path):if not os.path.exists(folder_path):os.makedirs(folder_path)result_path os.p…

Mac操作系统Safari 17全新升级:秋季推出全部特性

苹果的内置浏览器可能是Mac上最常用的应用程序(是的,甚至比Finder、超级Mac Geeks还要多)。因此,苹果总是为其浏览器Safari添加有用的新功能。在今年秋天与macOS Sonoma一起推出的第17版中,Safari可以帮助你提高工作效…

驱动day10

练习 基于platform实现 设备树 myplatform_homework{compatible "hqyj,myplatform_homework"; //用于获取节点reg <0x12345678 14>;interrupt-parent <&gpiof>; //引用父节点interrupts <9 0>; //这个节点引入的中断管脚led1-gpi…

搜索与图论-拓扑序列

为什么记录呢 因为不记录全忘了 虽然记了也不一定会看 有向无环图一定有拓扑序列邮箱无环图 - 拓扑图 入度为0的点作为起点入度为0的点入队列枚举出边 t->j删掉当前边&#xff0c;t->j . j的入度减1判断j的入度是否为0&#xff0c;来判断是否加入队列 有环&#xff1a; …

【JavaScript】数组的方法

当谈到 JavaScript 中的数组方法时&#xff0c;有很多内置的方法可用于操作和处理数组中的元素。下面是一些常用的数组方法&#xff0c;以及它们的详细解释&#xff1a; push(item1, item2, …): 将一个或多个元素添加到数组的末尾。 const array [1, 2, 3]; array.push(4, 5)…

.NET Core 开发文档资源

.NET Core 是一个开源的、跨平台的开发框架&#xff0c;用于构建各种类型的应用程序&#xff0c;包括 Web 应用、移动应用、桌面应用等。它提供了许多工具、库和运行时环境&#xff0c;以帮助开发人员构建高性能、可扩展的应用程序。从 .NET 5 开始&#xff0c;.NET Core 已经正…

​关于非易失性MRAM应用

作为一种磁性技术&#xff0c;MRAM本质上是抗辐射的。这使得独立版本在航空航天应用中很受欢迎&#xff0c;而且这些应用对价格的敏感度也较低。它相对较大&#xff0c;在内存领域&#xff0c;尺寸意味着成本。 MRAM还在企业存储中找到了一席之地&#xff0c;例如IBM的闪存核心…

我的创作纪念日:进程的概念、组成、特征;进程的基本状态;进程切换、原子操作、原语;进程间通信的方式;共享缓冲区、消息队列的本质、管道通信

一、进程的概念 如何区分这三个QQ进程&#xff1f;》除了名称之外&#xff0c;OS使用pid来唯一标识进程 二、进程的组成 PCB当中存储的都是OS在对进程进行管理时候的有用信息 PCB是给OS使用的一个数据结构&#xff0c;而程序段和数据段是给进程自己使用的&#xff0c;PCB是进…

提升代码可读性与可维护性:利用责任链模式优化你的Spring Boot代码

1. 基本介绍 责任链是一种非常常见的设计模式, 具体我就不介绍了, 本文是讲解如何在SpringBoot中优雅的使用责任链模式 1.1. 代码执行流程 基本步骤如下 : SpringBoot启动时, 需要获取 handler 对应Bean, 不同业务对应着不同的多个处理器, 比如 购票业务, 可能需要检查参数是…

docker高级(mysql主从复制)

数据库密码需要设置成自己的&#xff01;&#xff01;&#xff01; 1、创建容器master13307 #docker pulldocker run -p 13307:3306 --name mysql-master \ --privilegedtrue \ -v /mysql/mysql-master/log:/var/log/mysql \ -v /mysql/mysql-master/data:/var/lib/mysql \ -…

【Unity】【Amplify Shader Editor】ASE入门系列教程第二课 硬边溶解

黑色为0,白色为1 新建材质&#xff08;不受光照影响&#xff09; 拖入图片 设置 添加节点&#xff1a; 快捷键&#xff1a;K 组合通道&#xff1a;快捷键 V 完成图

spark底层为什么选择使用scala语言开发

Spark 底层使用 Scala 开发有以下几个原因&#xff1a; 基于Scala的语言特性 集成性&#xff1a;Scala 是一种运行在 Java 虚拟机&#xff08;JVM&#xff09;上的静态类型编程语言&#xff0c;可以与 Java 代码无缝集成。由于 Spark 涉及到与大量 Java 生态系统的交互&#x…

【Sublime Text 】Sublime Text 设置中文 超详细 持续更新中

Sublime Text 设置中文 超详细 持续更新中 概述开发环境一、Sublime Text 设置中文 概述 一个好的安装教程能够帮助开发者完成更便捷、更快速的开发。书山有路勤为径&#xff0c;学海无涯苦作舟。我是秋知叶i、期望每一个阅读了我的文章的开发者都能够有所成长。 开发环境 开…

后端返回文件流,前端怎么导出、下载(8种方法可实现)

在前端导出和下载后端返回的文件流时&#xff0c;可以使用以下几种方法&#xff1a; 使用window.open()方法&#xff1a; 在前端使用window.open()方法打开一个新的窗口或标签页&#xff0c;并将后端返回的文件流作为URL传递给该方法。浏览器会自动下载该文件。例如&#xff1a…

掌握 MyBatis<choose>标签:优化动态查询条件的利器

当谈到在Java应用程序中进行数据库访问时&#xff0c;MyBatis 是一个备受欢迎的持久层框架。它的强大之处在于提供了灵活性和可定制性&#xff0c;使得数据库操作变得更加简便。在这篇文章中&#xff0c;我们将深入介绍 MyBatis 中的<choose> 标签&#xff0c;它是一个有…

问道管理:逾4600股飘红!汽车板块爆了,多股冲击涨停!

A股商场今天上午全体低开&#xff0c;但其后逐级上行&#xff0c;创业板指数上午收盘大涨超越3%&#xff0c;北向资金也完成净买入38亿元。 别的&#xff0c;A股商场半年报成绩发表如火如荼进行中&#xff0c;多家公司发表半年报后股价应声大涨&#xff0c;部分公司股价冲击涨停…

《C和指针》笔记9: typedef

C语言支持一种叫作typedef的机制&#xff0c;它允许你为各种数据类型定义新名字。typedef声明的写法和普通的声明基本相同&#xff0c;只是把typedef这个关键字出现在声明的前面。例如&#xff0c;下面这个声明&#xff1a; char *ptr_to_char;把变量ptr_to_char声明为一个指向…