Java 运行时异常

异常分类

Java中所有的异常都继承自java.lang.Throwable类。Throwable类有两个直接子类,Error类和Exception类:

  • Error——程序无法处理的严重错误,编译器不做检查,通常JVM会终止线程的动作

  • Exception——它又分为运行时异常和编译期异常

运行时异常

运行时异常:RuntimeException——通常是由于逻辑错误产生的,常见的NullPointException,ClassCastException,IndexOutOfBoundsException等。运行时异常在默认情况下会得到自动处理,所以通常用不着捕获RuntimeException。RuntimeException是那些可能在Java虚拟机正常运行期间抛出的异常的超类,可能在执行方法期间抛出但未被捕获的RuntimeException的任何子类都无需在throws子句中进行声明。

运行时异常(RuntimeException)也叫非受检异常,主要的运行时异常有下列几种:

  • ArithmeticException - 算术逻辑运算异常
  • ArrayIndexOutOfBoundsException - 数组下标越界访问异常
  • IndexOutOfBoundsException - 下标越界异常
  • StringIndexOutOfBoundsException - 字符串截取下标越界
  • ArrayStoreException - 数据存储异常,写数组操作时,对象或数据类型不兼容
  • ClassCastException - 类型转换异常
  • IllegalArgumentException - 方法参数无效异常
  • IllegalThreadStateException - 非法线程状态异常,比如线程调用两次start方法
  • IllegalMonitorStateException - 某一对象试图等待对象的监视器,然而本身没有指定的监视器的线程
  • IllegalStateException - 无效状态异常
  • NullPointerException - 空指针异常,这个最常见,比如访问了空数组、方法等
  • NumberFormatException - 数据格式异常
  • SecurityException - 安全异常
  • IncompatibleClassChangeException - 不合法类变更异常
  • OutOfMemoryException - 内存不足异常
  • NoClassDefFoundException - 找不到类定义异常
  • IncompatibleTypeException - 不合法类型异常
  • UnsatisfiedLinkException - 无法连接异常
  • InternalException - 系统内部异常
  • EnumConstantNotPresentException - 枚举常量不存在异常

下面看一个不常见的ArrayStoreException异常:

private static void func(){
        //创建一个初始容量大小为2的字符串数组
        String[] a = new String[2];
        //Object是所有类的父类,Object数组指向a
        Object[] b = a;
        a[0] = "hello";
        System.out.println(b[0]);
        //java.lang.ArrayStoreException: java.lang.Integer
        //创建的数组已经是String类型了,再给它赋值Integer类型就会出现异常
        b[1] = Integer.valueOf(42);
    }

那么开发过程中分清这些异常有什么好处呢?当然是明确开发中可能发生的异常,并用合理的方式进行处理。比如说,

  1. 我们可以安装checkstyle等插件再加上合理的注解,如@NonNull。让IDEA警告代码可能出现崩溃的风险的地方。
  2. NullPointException通常不要去捕获该异常,而是通过判空校验的方法去解决。
  3. 在方法上加上@Transactional则表示该方法执行成功后自动提交,方法抛出RuntimeException及其子类时自动回滚。如果想要非运行时异常(如ParseException)也进行回归操作,则需要使用@Transactional(rollbackFor=Exception.class)。

编译期异常

编译期异常:NonRuntimeException——必须处理,否则程序编译无法通过,这类异常在编译时需要捕获,常见的有IOException,SQLException等

编译器异常也叫受检异常(CheckedException),除了RuntimeException以外的异常,都属于受检异常,它们都在java.lang库内部定义。Java编译器要求程序必须捕获声明抛出这种异常。一个方法必须通过throws语句在方法的声明部分说明它可能抛出但并未捕获的所有CheckedException。

  • java.lang.ClassNotFoundException
  • java.io.FileNotFoundException
  • java.io.IOException
  • java.sql.SQLException
  • java.net.SocketException
  • java.lang.CloneNotSupportedException
  • java.lang.IllegalAccessException
  • java.lang.InterruptedException
  • java.lang.NoSuchFieldException
  • java.lang.NoSuchMetodException

对可容错处理的情况使用受检异常(Checked Exception),对编程错误使用运行时异常(Runtime Exception)。另外,有以下准则,

  • 不要通过一个空的catch块忽略异常
  • 方法抛出的异常,应该与本身的抽象层次相对应
  • 在finally块中不要使用return、break或continue使finally块非正常结束
  • 不要直接捕获受检异常的基类Exception,一般作为补充没有考虑到的异常
  • 一个方法不应抛出超过5个异常
  • 在Javadoc的@throws标签中记录每个抛出的异常及其条件

自定义异常

自定义异常:自定义异常是继承Exception还是RuntimeException由异常本身的特点决定,我们业务代码的ApiException是继承的RunTimeException

自定义异常通常是我们自己根据业务特定自定义的异常信息,然后通过统一的全局异常处理对其进行格式化,如何定义一个全局异常处理类可以参考文末链接1的2.3节。

异常信息打印

通常,我们在开发过程中会捕获异常并打印异常信息相应的日志,但是部分异常信息不适合打印并暴露出去,详细信息可以参考文末链接2,主要的敏感异常如下,

  • FileNotFoundException(可能泄漏系统文件目录结构)
  • SQLException(可能泄漏数据库结构,遭受SQL注入攻击)
  • BindException(可能泄漏应用绑定的端口信息)
  • ConcurrentModificationException(可能泄漏线程不安全的信息)
  • InsufficientResourcesException(泄漏服务资源不足信息,可能遭遇DOS攻击)
  • MissingResourceException(可能泄漏资源枚举信息)
  • JarException(可能泄漏系统结构信息)
  • NotOwnerException(可能泄漏Owner枚举信息)
  • OutOfMemoryError(可能遭遇DOS攻击)
  • StackOverflowError(可能遭遇DOS攻击)

参考链接:

1、Spring Boot 异常处理 – @ExceptionHandler示例 · HowToDoInJava 中文系列教程 · 看云

2、ERR01-J. Do not allow exceptions to expose sensitive information - SEI CERT Oracle Coding Standard for Java - Confluence

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值