详解Java异常处理最佳实践及陷阱防范

前言

不管在我们的工作还是生活中,总会出现各种“错误”,各种突发的“异常”。无论我们做了多少准备,多少测试,这些异常总会在某个时间点出现,如果处理不当或是不及时,往往还会导致其他新的问题出现。所以我们要时刻注意这些陷阱以及需要一套“最佳实践”来建立起一个完善的异常处理机制。

异常分类

首先,这里我画了一个异常分类的结构图。

在JDK中,Throwable是所有异常的父类,其下分为”Error“和”Exception“。Error意味着出现了不可控的严重错误,例如OutOfMemoryError。Exception则细分为两类,受检异常(check)需要我们手动try/catch或者在方法定义中throws,编译器在编译的时候会检查其合法性。非受检异常(uncheck)则不需要我们提前处理。这些简单的概念对于开发人员来说都是必须掌握的,这里就展示个图例,不做详细的描述了,我们的”正餐“还在后面。

重新认识try/catch/finally

说到异常处理,这里就不得不提try/catch/finally。try不可以单独存在,要么搭配catch,要么搭配finally,或者三者并存。

1、try代码块:监视代码块的执行,发现对应的的异常则跳转至catch,若无catch则直接到finally块。

2、catch代码块:发生对应的异常会执行里面的代码,要么处理,要么向上抛出。

3、finally代码块:不管是否有异常,都必执行,一般用来清理资源,释放连接等。然而有以下几种情况不会执行到这里的代码。

  1. 代码执行流程未进入try代码块。
  2. 代码在try代码块中发生死循环、死锁等状态。
  3. 在try代码块中执行了System.exit()操作。

try/catch/finally陷阱

下面介绍两个我们在使用tcf的时候可能会遇到的陷阱。

代码1

public class TCFDemo {
  public static void main(String[] args) {
    //11
    System.out.println(returnVal());
  }

  static int returnVal(){
    int a = 1;
    int b = 10;
    try{
      return ++a;
    }finally {
      return ++b;
    }
  }
}

陷阱1:在finally中添加return语句,这样会覆盖掉try代码return的值,假如业务逻辑比较复杂,这里是很容易掉坑的,不利于排查错误。

代码2

public class TCFDemo {
  public static void main(String[] args) {
    Lock lock = new ReentrantLock();
    try{
      //有可能加锁失败
      lock.lock();
      //dost
    }finally {
      lock.unlock();
    }
  }
}

陷阱2:由于lock方法在加锁的时候有可能会抛出Uncheck异常,如果在try代码块中,必然会执行unlock方法,此时由于并没有加锁成功,所以会抛出IllegalMonitorStateException,这样一来后者的异常就覆盖掉了前者加锁失败的异常信息,所以我们应该把加锁的方法挪至try代码块外面。

最佳实践

好了,前面简单介绍了异常的分类以及try/catch/finally的注意事项,现在可以总结一下我们在异常处理的时候有哪些”最佳实践“了。

  1. 当需要向上抛出异常的时候,需根据当前业务场景定义具有业务含义的异常,优先使用行业内定义的异常或者团队内部定义好的。例如在使用dubbo进行远程服务调用超时的时候会抛出DubboTimeoutException,而不是直接把RuntimeException抛出。
  2. 请勿在finally代码块中使用return语句,避免返回值的判断变得复杂。
  3. 捕获异常具体的子类,而不是Exception,更不是throwable。这样会捕获所有的错误,包括JVM抛出的无法处理的严重错误。
  4. 切记更别忽视任何一个异常(catch住了不做任何处理),即使现在能确保不影响逻辑的正常运行,但是对于将来谁都无法保证代码会如何改动,别给自己挖坑。
  5. 不要使用异常当作控制流程来使用,这是一个很奇葩也很影响性能的做法。
  6. 清理资源,释放连接等操作一定要放在finally代码块中,防止内存泄漏,如果finally块处理的逻辑比较多且模块化,我们可以封装成工具方法调用,代码会比较简洁。

结尾

小小的异常,有大大的学问,你觉得呢?

以上所述是小编给大家介绍的Java异常处理最佳实践及陷阱防范详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 通过实践了解如何处理Java异常

    大多数团队都使用了几种最佳实践.以下是帮助你入门或改进异常处理的9个最重要的内容. 1.在finally块中清理资源或使用Try-With-Resource语句 在try块中使用资源是很频繁的,比如InputStream,之后需要关闭它.这些情况中的一个常见错误是在try块结束时关闭资源. public void doNotCloseResourceInTry() { FileInputStream inputStream = null; try { File file = new File("

  • Java异常处理的12条军规总结

    异常的概念 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error:如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出java.lang.ArithmeticException的异常. 异常发生的原因有很多,通常包含以下几大类: •用户输入了非法数据. •要打开的文件不存在. •网络通信时连接中断,或者JVM内存溢出. 这些异常有的是因为用

  • Java异常处理中的各种细节汇总

    前言 今天我们来讨论一下,程序中的错误处理. 在任何一个稳定的程序中,都会有大量的代码在处理错误,有一些业务错误,我们可以通过主动检查判断来规避,可对于一些不能主动判断的错误,例如 RuntimeException,我们就需要使用 try-catch-finally 语句了. 有人说,错误处理并不难啊,try-catch-finally 一把梭,try 放功能代码,在 catch 中捕获异常.处理异常,finally 中写那些无论是否发生异常,都要执行的代码,这很简单啊. 处理错误的代码,确实并

  • Java异常处理与throws关键字用法分析

    本文实例讲述了Java异常处理与throws关键字用法.分享给大家供大家参考,具体如下: Java异常处理 认识异常: 1.异常是导致程序中断运行的一种指令流,如果不对异常进行正确处理,则可能导致程序的中断执行,造成不必要的损失. 2.异常范例 空指针异常 Exc e=null; System.out.println(e.i); 除0异常 int a=10; int b=0; System.out.println(a/b); 3.处理异常 异常格式: try{ 异常语句: } catch(Exc

  • 如何利用Retrofit+RxJava实现网络请求的异常处理

    通常情况下我们在与服务器进行通信的时候,不一定就不会出错,有时会出现其他的错误,这个时候我们只要和服务器约定好各种异常,在返回结果处进行判断,到底是执行错误,还是返回正常数据.具体的思路大致就是这样.这里我们定义ExceptionHandle,这里我参考网上的东西,然后稍微做了一些改动. ExceptionHandle public class ExceptionHandle { private static final int UNAUTHORIZED = 401; private stati

  • 详解Java异常处理最佳实践及陷阱防范

    前言 不管在我们的工作还是生活中,总会出现各种"错误",各种突发的"异常".无论我们做了多少准备,多少测试,这些异常总会在某个时间点出现,如果处理不当或是不及时,往往还会导致其他新的问题出现.所以我们要时刻注意这些陷阱以及需要一套"最佳实践"来建立起一个完善的异常处理机制. 异常分类 首先,这里我画了一个异常分类的结构图. 在JDK中,Throwable是所有异常的父类,其下分为"Error"和"Exception&

  • 详解Android单元测试最佳实践

    目的 充分的单元测试就是提高代码质量最有效的手段之一,而单元测试严重依赖代码的可测试性,本文主要通过一个简单的DEMO演示如何对Android原生应用进行单元测试,同时示例代码采用MVP模式以提高代码的可读性和可测试性 简介 在Android原生应用开发中,存在两种单元测试:本地JVM测试和Instrumentation测试.本文仅介绍本地JVM测试 本地jvm的单元测试 这种方式运行速度快,对运行环境没有特殊要求,可以很方便的做自动化测试,是单元测试首选的方法 Instrumentation测

  • Java编程异常处理最佳实践【推荐】

    Java中的异常处理不是一个简单的话题.初学者很难理解,甚至有经验的开发人员也会花几个小时来讨论应该如何抛出或处理这些异常.这就是为什么大多数开发团队都有自己的异常处理的规则和方法.如果你是一个团队的新手,你可能会惊讶于这些方法与你之前使用过的那些方法有多么不同.常见的异常类型: NullPointerException -空指针引用异常 ClassCastException-类型强制转换异常 lllegalArgumentException-传递非法参数异常 ArithmeticExcepti

  • 详解java实践SPI机制及浅析源码

    1.概念 正式步入今天的核心内容之前,溪源先给大家介绍一下关于SPI机制的相关概念,最后会提供实践源代码. SPI即Service Provider Interface,属于JDK内置的一种动态的服务提供发现机制,可以理解为运行时动态加载接口的实现类.更甚至,大家可以将SPI机制与设计模式中的策略模式建立联系. SPI机制: 从上图中理解SPI机制:标准化接口+策略模式+配置文件: SPI机制核心思想:系统设计的各个抽象,往往有很多不同的实现方案,在面向的对象的设计里,一般推荐模块之间基于接口编

  • 详解Java实践之适配器模式

    目录 一.前言 二.适配器模式介绍 三.案例场景模拟 3.1.场景模拟工程 3.2.场景简述 3.2.1.注册开户MQ 3.2.2.内部订单MQ 3.2.3.第三方订单MQ 3.2.4.查询用户内部下单数量接口 3.2.5.查询用户第三方下单首单接口 四.代码实现 4.1.工程结构 4.2.Mq接收消息实现 五.适配器模式重构代码 5.1.工程结构 5.2.代码实现(MQ消息适配) 5.2.1.统一的MQ消息体 5.2.2.MQ消息体适配类 5.2.3.测试适配类 5.3.代码实现(接口使用适配

  • 详解Java实践之抽象工厂模式

    目录 一.前言 二.开发环境 三.抽象工厂模式介绍 四.案例场景模拟 4.1.场景模拟工程 4.2.场景简述 4.2.1.模拟单机服务 RedisUtils 4.2.2.模拟集群 EGM 4.2.3.模拟集群 IIR 4.3.单集群代码使用 4.3.1.定义使用接口 4.3.2.实现调用代码 五.代码实现 5.1.工程结构 5.2.ifelse实现需求 5.3.测试验证 六.抽象工厂模式重构代码 6.1.工程结构 6.2.代码实现 6.2.1.定义适配接口 6.2.2.实现集群使用服务 6.2.

  • 详解Java实践之建造者模式

    目录 一.前言 二.开发环境 三.建造者模式介绍 四.案例场景模拟 4.1.场景模拟工程 4.2.场景简述 4.2.1.物料接口 4.2.2.吊顶(ceiling) 4.2.3.涂料(coat) 4.2.4.地板(floor) 4.2.5.地砖(tile) 五.代码实现 5.1.工程结构 5.2.ifelse实现需求 5.3. 测试验证 六.建造者模式重构代码 6.1.工程结构 6.2.代码实现 6.2.1.定义装修包接口 6.2.2.装修包实现 6.2.3.建造者方法 6.3.测试验证 七.总

  • 详解Java中AbstractMap抽象类

    jdk1.8.0_144 下载地址:http://www.jb51.net/softs/551512.html AbstractMap抽象类实现了一些简单且通用的方法,本身并不难.但在这个抽象类中有两个方法非常值得关注,keySet和values方法源码的实现可以说是教科书式的典范. 抽象类通常作为一种骨架实现,为各自子类实现公共的方法.上一篇我们讲解了Map接口,此篇对AbstractMap抽象类进行剖析研究. Java中Map类型的数据结构有相当多,AbstractMap作为它们的骨架实现实

  • 详解Java 类的加载机制

    一.类的加载机制 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构.类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接

  • 详解Java 中的 AutoCloseable 接口

    一.前言 最近用到了 JDK 7 中的新特性 try-with-resources 语法,感觉到代码相对简洁了很多,于是花了点时间详细学习了下,下面分享给大家我的学习成果. 二.简单了解并使用 try-with-resources语法比较容易使用,一般随便搜索看下示例代码就能用起来了.JDK 对这个语法的支持是为了更好的管理资源,准确说是资源的释放. 当一个资源类实现了该接口close方法,在使用try-with-resources语法创建的资源抛出异常后,JVM会自动调用close 方法进行资

随机推荐