异常时相对于return的一种退出机制,能够由系统触发,也可由程序经过throw语句触发,异常能够经过try/catch语句进行捕获并处理,若是没有捕获,则会致使程序退出并输出异常栈信息,异常有不一样的类型,全部异常类都有一个共同的父类Throwable,下面咱们先从Throwable开始介绍。html
Throwable
是全部异常类的父类,有四个构造方法java
public Throwable(Throwable cause) public Throwable(String message, Throwable cause) public Throwable(String message) public Throwable()
主要有两个类,一个是message,表示异常的消息,一个是cause,表示触发该异常的其余异常,异常能够造成一个异常链,上层的异常由底层到的异常触发,cause表示底层异常。程序员
java定义了很是多的异常类,来表示各类类型的异常,下面的图示是部分的异常类:spring
Throwable是全部异常类的基类,它有两个子类:Error和Exception。数据库
操做系统或者虚拟机发生的错误,这个时候程序是跑不起来的,代码是没法处理的,通常表示系统错误或者资源耗尽,由java系统本身处理,好比图示中给出的:虚拟机错误、栈溢出、内存溢出等错误浏览器
表示应用程序错误,是能够经过代码处理的,有两大类:一类是受检异常(checked exception),一类是非受检异常(uncheck exception),也就是runtime异常,他两的区别就在于java是如何对待他们的,受检异常,java会要求强制进行处理,否则编译时不经过的,对于非受检异常则没有这个强制性的要求。app
解释函数
该怎么理解受检异常和非受检异常呢,个人理解就是作某件事的时候咱们可以顺利的按照咱们预期的作完,可是实际上呢可能会出现各类各样的状况,这种可能出现的状况就把他称之为异常,这种异常有的咱们能处理,有的咱们不能处理,能处理的就把它称做为受检异常,不能处理的称做为非受检异常。spring-boot
好比说,客户端发送一个请求,要查询数据库,那有可能找到有可能没找到,没找到的话,就应该抛出runtime异常,再好比要去读取文件,文件多是不存在的,那就应该抛出checked exception,这其实就是bug,咱们应该去处理的。测试
怎么理解呢,好比读取文件,当文件不存在,发生异常,能处理么,固然能够处理啊,怎么处理,把文件路径改为正确的不就好了。从某种意义上来讲,checked异常是真正的bug
没有办法处理的状况,好比说用户输入ID为2,查询记录能找到,可是若是输入2000就找不到了,这里的找不到就是一种异常状况,就须要产生一个运行时异常也就是非受检异常。
上面咱们提到的受检异常 unchecked exception
和运行时异常 RuntimeException
都是从java语法层面来讲的,那从程序开发者的角度来讲,分为两类:已知异常和未知异常。
已知异常和未知异常,其实就在于咱们程序员是否主动的去处理异常。
在使用spring-boot进行开发到的时候,有时咱们须要对程序中抛出的异常进行统一的处理,spring-boot预留了响应的扩展点,咱们只须要按照要求的方式去自定义本身的实现便可。
@ControllerAdvice public class GlobalExceptionAdvice { @ExceptionHandler(value = Exception.class) public void handleHttpException(HttpServletRequest req, Exception ex){ } }
@ControllerAdvice
代表GlobalExceptionAdvice是一个异常的处理类,具体的处理方法经过 @ExceptionHandler
进行标记,经过value来指定可以处理的异常类型。异常的处理方法须要传入两个参数,一个是HttpServletRequest请求对象,能够从这里获取请求相关的一些信息,好比请求的url或者参数等,另外一个是Exception就是抛出的异常。
咱们在异常的处理方法中打印一条语句
@ControllerAdvice public class GlobalExceptionAdvice { @ExceptionHandler(value = Exception.class) public void handleHttpException(HttpServletRequest req, Exception ex){ System.out.println("发生异常了"); } }
而后再Controller里抛出一个异常
@RestController public class BannerController { @RequestMapping(value = "/v2/banner", method = {RequestMethod.GET}) public String test() throws Exception { throw new Exception("我抛出来的"); } }
启动程序后在浏览器中访问路由,能够看到在控制台中打印出了预期的信息
固然在实际开发中,咱们可能要多异常进行区分,该抛出什么类型的异常,异常处理函数可也不仅一个,还要对返回的异常信息进行自定义。
当咱们须要自定义异常类的时候,是该继承自exception呢,仍是继承RuntimeException?下面咱们就来讨论一下。
当用户访问一个不存在的资源的时候,很明显这种状况咱们是处理不了的,并且这种状况咱们是能够判断出来的,因此这里应该使用Runtime异常。
HttpException
是全部自定义运行时异常类的基类,这里定义两个状态码,一个code是咱们业务层面的定义,一个httpStatusCode是http请求的,资源不存在的异常定义为 NotFoundException
在controller里面抛出这个异常,
那以前定义的 GlobalExceptionAdvice
可以监听到这个异常呢?
固然能,NotFoundException
是 HttpException
的子类,HttpException
是 RuntimeException
的子类,RuntimeException
又是 Exception
的子类,@ExceptionHandler(value = Exception.class)
全局异常处理器里指定的可以处理的异常类是 Exception
天然也能处理 NotFoundException
。
可是这里也有不一样的地方,咱们自定义的 HttpException
是多了两个扩展字段的,code
和 httpStatusCode
,因此在全局异常处理器里须要对异常的类型进行判断,若是是自定义的就须要添加这两个字段。
这里呢有两种方式进行处理:一种是在以前的异常处理方法里面,进行类型判断,另外一种呢是能够再添加一个异常处理方法,专门处理自定义异常类
这里咱们能够考虑一下,当咱们抛出 NotFoundException
异常的时候,是会进入哪个异常处理方法里?仍是说两个都进呢?
咱们能够来试验一下,启动程序后,看看在控制台打印的是什么
在浏览器里访问路由之后,控制台显示了handleHttpException异常处理方法里到的打印语句输出的内容。
能够看到多个异常处理方法时能够同时存在的,各自处理本身所能处理的异常类。
下篇文章,咱们来探讨一下,如何自定义异常的返回信息,敬请关注,博客原文
欢迎你们去 个人博客 瞅瞅,里面有更多关于测试实战的内容哦!!