1.概念
程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常。
Java的基本理念:结构不佳的代码不能运行。发现代码的理想时机是在编译阶段,也就是你试图运行程序之前。然而,编译期间并不能找到所有的错误,余下的问题必须要在运行期间解决。这就需要错误源能通过某种方式,把错误信息传给接收者。
异常处理机制就是这样的错误报告机制。
2.异常体系
2.1Throwable
(1)getMessage():获取detail message即相关的错误描述信息。
(2)toString():返回包含异常类名+getMessage()。
(3)printStackTrace():打印详细异常信息和异常抛出路径(不推荐使用,可使用log代替)。
2.2Error
Error是Throwable的子类之一,包含的方法主要来自于继承自Throwable的那些。Error我们开发者接触到的不多,一般都是和虚拟机相关的问题,如:系统崩溃、虚拟机错误、系统资源如内存不足等,如:OutOfMemoryError等。
Error靠程序自身是无法解决的,一般JVM会选择终止程序。
2.3Exception
Exception大致分为两类:
(1)可检查异常(checked exceptions)
Exception子类中除去RuntimeException以及其子类的异常都是可检查异常。
程序经过编译时,编译器会要求对此类异常进行处理(throws/try-catch)。
处理方式也就是:throws/try-catch。
(2)不可检查异常(unchecked exceptions)
RuntimeException以及他的子类。
程序经过编译时,编译器不会要求对此类异常进行处理(throws/try-catch)。RuntimeException以及他的子类和Error都属于不可检查异常。
对于RuntimeException的子类我们开发者要特别注意,因为编译器不会提示我们,我们要给与合适的处理(但像空指针、数组下标越界等异常都可以通过代码规避掉,还有些如NumberFormatException等在不确定的情况下要使用异常处理机制,举例:在解析JSON字符串形式的数字时,可能存在数字格式错误)。
3.自定义异常
注意以下要点:
(1)所有异常都必须是 Throwable 的子类。
(2)果希望写一个检查性异常类,则需要继承 Exception 类。
(3)如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
4.异常处理
4.1声明异常
在方法上通过throws关键字声明异常:
public getInfo(String name) throws FileNotFoundException
4.2抛出异常
向方法栈上方抛出异常,让调用者去处理异常
throw new MyException();
4.3捕获异常
通过try-catch语句捕获异常
try{
code more code
}catch(Exception){
handler for this type
}
4.4再次抛出异常(异常链)
语句中再次抛出异常(异常链)在catch中可以再抛出一个异常,这样做的目的是改变异常的类型。
比如:执行servlet的代码可能不想知道发生错误的细节原因,但希望明确的知道servlet是否又问题。这时,可以用ServletException去封装原始异常。
try
{
access the database
}
catch(SQLExeption e)
{
Throwable se = new ServletException();
se.initCause(e);
throw se;
}
这样做在捕获到异常时就可以使用如下方式,重新得到原始异常而补丢失细节:
Throwable e = se.getCause();
5.异常拦截与统一处理
使用拦截器拦截、处理异常
@ControllerAdvice:将会拦截Controller的相应异常
@ControllerAdvice
public class MyExceptionHandler {
// Annotation for handling exceptions in specific handler classes and/or handler methods.
// 转发到系统的错误处理
// @ExceptionHandler(TestException.class)
// public String handleException(Exception e, HttpServletRequest request) {
// Map map = new HashMap<>();
// /*对异常信息进行处理*/
// //传入我们自己的错误状态码 4xx 5xx
// Integer statusCode = (Integer) request
// .getAttribute("javax.servlet.error.status_code");
// request.setAttribute("javax.servlet.error.status_code", 400);
// map.put("code", "user.notexist");
// map.put("message", "用户出错啦");
// request.setAttribute("ext", map);
//
// //转发到/error
// return "forward:/error";
// }
// Annotation for handling exceptions in specific handler classes and/or handler methods.
@ExceptionHandler(TestException.class)
@ResponseBody
public Map handleException(Exception e, HttpServletRequest request) {
Map map = new HashMap<>();
/*对异常信息进行处理*/
//传入我们自己的错误状态码 4xx 5xx
Integer statusCode = (Integer) request
.getAttribute("javax.servlet.error.status_code");
map.put("code", statusCode);
map.put("message", "自定义异常出错了!");
//转发到/error
return map;
}
}
//调用
@RequestMapping({"/errorTest"})
public String errorTest() {
throw new TestException("测试自定义异常");
}
6. springboot自定义异常数据和页面
在templates
文件或static
静态资源目录下创建对应的目录和文件即可,springboot会默认先从templates
目录下寻找,其次在static
目录下寻找,如果还是没有则使用系统默认的。