异常
错误
程序运行时发生的不被期望的事件,阻 ⽌了程序按照预期正常执行。常见程序错误分三类:
- 编译错误:没有遵循语法规范。
- 运行时错误:程序在执行时发生的错误。
- 逻辑错误:程序没有按照预期的逻辑顺序执行。
Java 异常体系
个 java.lang.Throwable 类是 Java 中所有错误和异常的超类,其派生的两个子类分别为:Error、Exception。
Error
包含大量子类,用于抽象出错后程序无法处理的情况,例如:OutOfMemoryError。
Exception
包含大量子类,用于抽象程序本身可以处理的异常。例如:ArrayIndexOutOfBoundException。同时 Exception 又派生出量大子类:
- 运行时异常(不可查异常):RuntimeException 类及其子类,例如:ArrayIndexOutOfBoundsException。ClassNotFoundException。
- 非运行时异常(编译时可查异常):所有 Exception 类及其子类(RuntimeException 类及其子类除外),例如:IOException。
Java 内置异常体系分类
非运行时异常(编译时可查异常)
必须要在方法里捕获或者抛出。
- ClassNoFoundException 应 ⽤程序试图加载类,找不到对应的类
- IllegalAccessException 拒绝访问 ⼀个类的时候
- NoSuchFieldExcetion 请求的变量不存在
- NoSuchMethodException ⽅法不存在
- ……
运行时异常(不可查异常)
- ArrayIndexOutOfBoundsException 数组索引越界
- ClassCastException 强制失败抛出异常
- NullPointerException 需要对象的地 ⽅使 ⽤ null 时,抛出该异常
- NumberFormatException 将字符串转换成 ⼀种数值类型,但该字符串不能转换为适当 格式时,抛出该异常
- ……
Throwable 类核心方法
- public String getMessage():异常的详细信息。
- public Throwable getCause():异常原因。
- public void printStackTrace():打印错误的堆栈信息,即错误输出流,可以看到错误原因和所在位置。
- public StackTraceElement [] getStackTrace():堆栈层次的数组,下标为 0 的元素代表栈顶,最后 ⼀个元素代表 ⽅法调 ⽤堆栈的栈底。
package com.javase.demo;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
class DemoApplicationTests {
@Test
public void tryCatchTesting() {
try {
int result = 2/0;
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();//打印错误的堆栈信息。可以看到错误原因和所在位置。
String msg = e.getMessage();
StackTraceElement[] arr = e.getStackTrace();
}
}
}
//java.lang.ArithmeticException: / by zero
//at com.javase.demo.DemoApplicationTests.tryCatchTesting(DemoApplicationTests.java:15
Try Catch 进行异常捕获
- try 后 ⾯跟 ⼀个或多个 catch 块,或 ⼀个 finally 块,或两者的组合
- catch 不能独立于 try 而单独存在
- 如果代码没有匹配到对应的异常类进 ⾏捕获,则默认打印异常堆栈
- 代码中发 ⽣异常,异常被抛给第 ⼀个 catch 块, 如果不匹配则继续往下 ⼀个 catch 进 ⾏传递
- finally 代码块中的代码总会被执 ⾏
- try,catch 和 finally 块有两种可能的组合:try-catch-finally 或 try-finally
try {
//发生异常的代码(此处中断,产生异常,进入catch代码块)1
//其他代码(不会执行)
//return 10 4
} catch (AException e) { //精确捕获异常A 2
e.printStackTrace();
} catch (BException e){ //精确捕获异常B
e.printStackTrace();
} finally {
//一定会执行(释放资源等……) 3
//return -10; 4(最终返回-4 ,取代return 10)
}
异常处理 throws/throw 关键
throws 关键字
throws 声明异常,往外抛出。
语法:throws⼦句放在 ⽅法参数列表的右括号之后,⼀个 ⽅法可以声明抛出多个异常, 多个异常之间 ⽤逗号隔开。
@Test
public void readChar() throws IOException, RemoteException {
int input = System.in.read();
}
throw 关键字
try catch 中捕获了异常,处理 ⽅法
- 捕获当前异常。
- 捕获自己处理然后继续往外部抛异常
//方法中使用throw抛出异常,必须在方法签名中使用throws声明抛出的异常类型(编译时异常)
public static void readChar() throws IOException {
try {
int input = in.read();
} catch (IOException e) {
System.out.println("出异常了");//1
throw new IOException("异常信息");
}
}
//调用者:自己捕获异常,自己处理。
public static void main(String[] args) {
try {
readChar();
} catch (IOException e) {
System.out.println("main函数异常");//2
}
}
//调用者:继续往外部抛异常
public static void main(String[] args) throws IOException {
readChar();
}
总结
当抛出(throw)⼀个被检查的异常,我们必须使 ⽤ try-catch 块来处理它,或者在 ⽅法声明中使 ⽤ throws 子句继续往外抛
自定义异常
JDK 内置的异常不足以满足生产环境的需求,生产环境中会出现各种各样的异常。自定义异常可以让业务更清晰。
异常都是继承 ⾃ Exception 类,所以我们要自定义的异常也需要继承 Exception 这个基类。
自定义异常类
public class UserNotEnoughException extends Exception{
private int code;
private String message;
public UserNotEnoughException(){
super();
}
public UserNotEnoughException(int code, String message) {
super(message);
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
方法中使用自定异常
public static void main(String[] args) {
try {
test();
} catch (UserNotEnoughException e) {
e.printStackTrace();
int code = e.getCode();
String message = e.getMessage();
System.out.println("code="+code + ", msg="+ message);
}
}
public static void test() throws UserNotEnoughException {
throw new UserNotEnoughException(-1,"人员不够");
}