Java基础知识-10-异常 try cach finall

用于解决程序在运行过程中产生的意外情况。语法错误或逻辑错误不算是异常。

一提到异常,大家难免会想到几个关键字。分别是:

try cach finally throw throws

他们都分别代表什么意思呢

try cach finally

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
java复制代码try{
可能会产生异常代码块
}catch(异常类型 ex){
对异常进行处理
//调试时一般会打印出调试信息
//ex.printStackTrace();
}catch(异常类型 ex){
对异常进行处理
//调试时一般会打印出调试信息
//ex.printStackTrace();
}finally{
//无论前面异常执行不执行,这里一定会被执行的代码
//除非前面强制终止,System.exit(1) //终止java虚拟机
//这里不要用return,否则会屏蔽前面的return
//一般在这里进行清理、释放资源等工作
}

throw throws

throws:

声明将要抛出何种类型的异常

1
2
3
4
java复制代码//下面的函数可能会抛出 异常类型1,异常类型2 这两种类型的异常.
public void 方法名() throws 异常类型1,异常类型2{
可能产生异常的代码
}

其本身不处理异常,只负责声明和抛出,使用它的人来处理异常

1
2
3
4
5
6
java复制代码调用存在异常声明的方法时
try {
方法名();//方法调用
}catch(异常类型 ex){
处理异常
}

throw:

主动/手动抛出一些业务逻辑上的异常,自己手动创建要抛出的异常

1
2
3
4
5
6
7
8
java复制代码public void 方法名(){
try {
if(业务异常)
throw new Exception("业务异常描述");
}catch(Exception ex){//捕获异常
//处理异常
}
}
1
2
3
4
5
6
7
8
9
10
11
12
java复制代码public void 方法名() throws Exception{
if(业务异常){
throw new Exception("业务异常描述");
}
}

//调用
try {
方法名();
}catch(Exception ex){//捕获异常
//处理异常
}

⚠️:throw和throws有本质的区别。不要混为一谈。

throw是抛出异常阶段 的方案:

抛出异常有两种:一种是系统自动产生异常并抛出,一种是手动创建异常抛出(throw)

throws是捕获异常阶段 的方案:

捕获异常处理的方案有两种,一种是try/catch直接处理,一种是抛给别人处理(throws)

自定义异常

定义一个类,继承自异常类

1
2
3
4
5
6
java复制代码public class MyException extends Exception{

public MyException(){//构造方法
super("异常描述");//调用父类构造方法
}
}

之后就可以在业务代码中 throw自己定义的异常了。

异常选择

  1. 如果父类中的方法没有throws异常,那么,子类中重写该方法时,也不能throws异常。对自己编写的可能出现异常的代码,只能自己try/catch
  2. 一个方法A中调用了方法 a1,a2,a3。那么,一般情况下a1,a2,a3建议用throws抛出异常,A中对异常进行try/catch。

异常链

多重嵌套抛出异常时,将异常信息一个一个的串联起来抛出的机制。否则只能看到最后一个异常。

  • 方式1
    throw Exception("本异常描述信息",捕获的异常)
  • 方式2
1
2
3
php复制代码    Exception ex = new Exception("本异常描述信息");
ex.initCause(捕获的异常);
throw ex;

异常实际案例

接下来,举一个实际项目中的异常捕获方式。但并不是唯一方式。

1.自定义一个全局异常捕获类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
java复制代码/**
* 全局异常捕获
*/
@ControllerAdvice
public class GlobalExceptionInterceptor {

private Logger log = LoggerFactory.getLogger(getClass());


/**
* 处理ServiceException异常 //自定义异常
*/
@ExceptionHandler(value = ServiceException.class)
@ResponseBody
public RespResult serviceExceptionHandle(ServiceException se) {
log.error("自定义异常堆栈:"+ ThrowableUtil.getStackTrace(se));
//对自定义异常处理的业务
return respBody;
}


/**
* 在 @RequestBody 上 加validate 校验参数失败后抛出的异常是
* MethodArgumentNotValidException异常。
* 参数为空,或没传参数都会抛此异常
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public RespResult MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
//参数校验异常处理逻辑
}

/**
* 在@RequestParam的参数没传时 抛这个异常
* MissingServletRequestParameterException 。
* 注意:是参数没传会抛,不是参数为空会抛
*/
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseBody
public RespResult MissingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
//参数校验异常处理逻辑
}

/**
* 处理请求json格式不成器的异常:HttpMessageNotReadableException
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseBody
public RespResult HttpMessageNotReadableExceptionHandler(HttpMessageNotReadableException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
//请求体校验异常处理逻辑
}


/**
* 唯一索引重复异常:MySQLIntegrityConstraintViolationException
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
@ResponseBody
public RespResult SQLIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) {
// 打印堆栈信息
log.error(ThrowableUtil.getStackTrace(e));
String message = e.getMessage();
//唯一索引异常处理逻辑
}

...
其他类型异常捕获及处理
}

2.自定义异常类

我们看到,在上面全局异常捕获类中,有一个自定义异常类。具体内容如下:

在业务处理中,遇到需要抛异常的地方,你就可以构造一个这样的异常,然后抛出去,就会被全局异常捕获并处理了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码public interface ExceptionEnumInterface {

/**
* 错误码,为200表示正常
* @return
*/
String getCode();

/**
* 错误说明,code为200时返回null,否则返回错误说明<br/>
* 可包含占位符,占位符格式为中括号加数字表示,如{0}, {1},表示替换为第0个、第1个参数
* @return
*/
String getMsg();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
java复制代码public class ServiceException extends RuntimeException{
private ExceptionEnumInterface errorEnum;
private Object[] args;
private Exception e;

/**
* 构造一个包含特定异常码的业务异常,当异常描述中饮食可替换的占位符时,可用args中参数来替换占位符<br/>
* 占位符格式为中括号加数字表示,如{0}, {1},表示替换为第0个、第1个参数
* @param errorEnum
* @param args
* @return
*/
public static ServiceException of(ExceptionEnumInterface errorEnum, Object...args) {
return new ServiceException(errorEnum, args);
}

/**
* 构造一个包含特定异常码的业务异常,当异常描述中饮食可替换的占位符时,可用args中参数来替换占位符<br/>
* 占位符格式为中括号加数字表示,如{0}, {1},表示替换为第0个、第1个参数
* @param errorEnum
* @param args
* @return
*/
public static ServiceException of(ExceptionEnumInterface errorEnum, Exception e, Object...args) {
return new ServiceException(errorEnum,e,args);
}

/**
* 通过异常枚举接口来返回特定的业务异常
* @param errorEnum
* @param args
*/
private ServiceException(ExceptionEnumInterface errorEnum, Object...args) {
super(ExceptionEnumUtil.getErrorEnumMsg(errorEnum, args));
this.errorEnum = errorEnum;
this.args = args;
}

/**
* 通过异常枚举接口来返回特定的业务异常
* @param errorEnum
* @param args
*/
private ServiceException(ExceptionEnumInterface errorEnum, Exception e, Object...args) {
super(ExceptionEnumUtil.getErrorEnumMsg(errorEnum, args));
this.errorEnum = errorEnum;
this.args = args;
this.e = e;
}

public ExceptionEnumInterface getErrorEnum() {
return errorEnum;
}

public Object[] getArgs() {
return args;
}

public Exception getE() {
return e;
}
}
  1. 抛异常

1
2
3
4
5
java复制代码try {
//业务代码
} catch (Exception e) {
throw ServiceException.of(参数);
}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%