一、Java异常体系
Throwable: Throwable类是java语言中所有错误或异常的超类
Throwable是所有异常的根,java.lang.Throwable
首先说明一点,java中的Exception类的子类不仅仅只是像上图所示只包含IOException和RuntimeException这两大类,事实上Exception的子类很多很多,主要可概括为:运行时异常与非运行时异常。
一java异常体系结构
从上述图示可以看到,
Thorwable类(表示可抛出)是所有异常和错误的超类,两个直接子类为Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常, 这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。下面将详细讲述这些异常之间的区别与联系:
1、Error与Exception
Error是程序无法处理的错误,它是由JVM产生和抛出的,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。程序中应当尽可能去处理这些异常。
2、运行时异常和非运行时异常
运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常(unchecked),编译器不
强制用 try..catch 处理或用 throws 声明,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。
编译器强制普通异常必须 try..catch 处理或用 throws 声明继续抛给上层调用方法处理,所以普通异常也称为 checked 异常如IOException、SQLException等以 及用户自定义的Exception异常,一般情况下 不自定义检查异常
5个常见RuntimeException
1)java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
2)java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序
试图通过字符串来加载某个类时可能引发异常。
3)java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
4)java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生。
5)java.lang.IllegalArgumentException 方法传递参数错误。
6)java.lang.ClassCastException 数据类型转换异常
Final,finally,finalize的区别?
1. Final可以修饰类,方法,属性,如果在类上,类不能被继承,如果在方法上不能重写,如果在属性上值不能改。
2. Finally是和异常try…catch异常处理模块一同使用的语句块,它在最后一定被执行。
3. Finalize当堆中的对象没有任何引用时,这个方法会被调用,来做垃圾回收
return 最后执行
finally先与return执行
自定义异常
为什么要使用自定义异常,有什么好处?
1.我们在工作的时候,项目是分模块或者分功能开发的 ,基本不会你一个人开发一整个项目,使用自定义异常类就统一了对外异常展示的方式。
2.有时候我们遇到某些校验或者问题时,需要直接结束掉当前的请求,这时便可以通过抛出自定义异常来结束,如果你项目中使用了SpringMVC比较新的版本的话有控制器增强,可以通过@ControllerAdvice注解写一个控制器增强类来拦截自定义的异常并响应给前端相应的信息(关于springMVC控制器增强的知识有空再和大家分享)。
3.自定义异常可以在我们项目中某些特殊的业务逻辑时抛出异常,比如"中性".equals(sex),性别等于中性时我们要抛出异常,而Java是不会有这种异常的。系统中有些错误是符合Java语法的,但不符合我们项目的业务逻辑。
4.使用自定义异常继承相关的异常来抛出处理后的异常信息可以隐藏底层的异常,这样更安全,异常信息也更加的直观。自定义异常可以抛出我们自己想要抛出的信息,可以通过抛出的信息区分异常发生的位置,根据异常名我们就可以知道哪里有异常,根据异常提示信息进行程序修改。比如空指针异常NullPointException,我们可以抛出信息为“xxx为空”定位异常位置,而不用输出堆栈信息。
说完了为什么要使用自定义异常,有什么好处,我们再来看看自定义异常的毛病:
毋庸置疑,我们不可能期待JVM(Java虚拟机)自动抛出一个自定义异常,也不能够期待JVM会自动处理一个自定义异常。发现异常、抛出异常以及处理异常的工作必须靠编程人员在代码中利用异常处理机制自己完成。这样就相应的增加了一些开发成本和工作量,所以项目没必要的话,也不一定非得要用上自定义异常,要能够自己去权衡。
最后,我们来看看怎么使用自定义异常:
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
自定义异常可以用来在透传异常信息的传递,最终将异常返回到控制层自定义的Response中,这个看使用情况
自定义运行时异常
出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。
如果没有处理块,到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。
抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。
运行时异常是Exception的子类,也有一般异常的特点,是可以被Catch块处理的。只不过往往我们不对他处理罢了。
也就是说,你如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。
如果不想终止,则必须扑捉所有的运行时异常,决不让这个处理线程退出。
队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。
不应该由于异常数据而影响下面对正常数据的处理。在这个场景这样处理可能是一个比较好的应用,但并不代表在所有的场景你都应该如此。
如果在其它场景,遇到了一些错误,如果退出程序比较好,这时你就可以不太理会运行时异常,或者是通过对异常的处理显式的控制程序退出。
先定义错误码枚举
public enum OrderExceptionEnum { /** 未知异常 */ UNKNOWN_EXCEPTION("OE001","未知异常","warn"), /** 系统错误 */ SYSTEM_ERROR("OE002","系统错误","error") ; private String errorCode; private String errorMsg; private String errorType; OrderExceptionEnum(String errorCode, String errorMsg, String errorType) { this.errorCode = errorCode; this.errorMsg = errorMsg; this.errorType = errorType; } /** * Getter method for property <tt>errorCode</tt>. * * @return property value of errorCode */ public String getErrorCode() { return errorCode; } /** * Setter method for property <tt>errorCode</tt>. * * @param errorCode value to be assigned to property errorCode */ public void setErrorCode(String errorCode) { this.errorCode = errorCode; } /** * Getter method for property <tt>errorMsg</tt>. * * @return property value of errorMsg */ public String getErrorMsg() { return errorMsg; } /** * Setter method for property <tt>errorMsg</tt>. * * @param errorMsg value to be assigned to property errorMsg */ public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } /** * Getter method for property <tt>errorType</tt>. * * @return property value of errorType */ public String getErrorType() { return errorType; } /** * Setter method for property <tt>errorType</tt>. * * @param errorType value to be assigned to property errorType */ public void setErrorType(String errorType) { this.errorType = errorType; } }
再定义异常类
public class OrderPeriodException extends RuntimeException { private static final long serialVersionUID = 6958499248468627021L; /** 错误码 */ private String errorCode; /** 错误上下文 */ private ErrorContext errorContext; public OrderPeriodException(String errorCode, String errorMsg){ super(errorMsg); this.errorCode = errorCode; } public OrderPeriodException(OrderExceptionEnum orderExceptionEnum){ super(orderExceptionEnum.getErrorMsg()); this.errorCode = orderExceptionEnum.getErrorCode(); } public OrderPeriodException(String errorCode, String errorMsg,Throwable throwable){ super(errorMsg,throwable); this.errorCode = errorCode; } public OrderPeriodException(OrderExceptionEnum orderExceptionEnum,Throwable throwable){ super(orderExceptionEnum.getErrorMsg(),throwable); this.errorCode = orderExceptionEnum.getErrorCode(); } /** * Getter method for property <tt>errorCode</tt>. * * @return property value of errorCode */ public String getErrorCode() { return errorCode; } /** * Setter method for property <tt>errorCode</tt>. * * @param errorCode value to be assigned to property errorCode */ public void setErrorCode(String errorCode) { this.errorCode = errorCode; } /** * Getter method for property <tt>errorContext</tt>. * * @return property value of errorContext */ public ErrorContext getErrorContext() { return errorContext; } /** * Setter method for property <tt>errorContext</tt>. * * @param errorContext value to be assigned to property errorContext */ public void setErrorContext(ErrorContext errorContext) { this.errorContext = errorContext; } public static void main(String[] args) { try{ int i = 1/0; }catch (Exception e){ throw new OrderPeriodException(OrderExceptionEnum.SYSTEM_ERROR,e); } } }