要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
- 检查性异常:
最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。 - 运行时异常:
运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。 - 错误:
错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
一.Exception 类的层次
从继承关系可知:Throwable是异常体系的根,它继承自Object。Throwable有两个体系:Error和Exception,Error表示严重的错误,程序对此一般无能为力,例如:
1.OutOfMemoryError
:内存耗尽
2.NoClassDefFoundError
:无法加载某个Class
3.StackOverflowError
:栈溢出
而Exception则是运行时的错误,它可以被捕获并处理。某些异常是应用程序逻辑处理的一部分,应该捕获并处理。例如:
1.NumberFormatException
:数值类型的格式错误
2.FileNotFoundException
:未找到文件
3.SocketException
:读取网络失败
还有一些异常是程序逻辑编写不对造成的,应该修复程序本身。例如:
1.NullPointerException
:对某个null的对象调用方法或字段
2.IndexOutOfBoundsException
:数组索引越界
Exception又分为两大类:
1.RuntimeException
以及它的子类;
2.非RuntimeException
(包括IOException
、ReflectiveOperationException
等等)
Java规定:
必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception。
不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。
二.捕获异常
捕获异常使用try…catch语句,把可能发生异常的代码放到try {…}中,然后使用catch捕获对应的Exception及其子类
try {
Integer.valueOf("22m");
} catch (NumberFormatException e) {
e.printStackTrace();
}
在异常捕获的同时,我们希望同时输出异常的详细信息,大多数情况下会选择e.printStackTrace();
这个方法,但是他对于系统 的性能会有一定的影响,先不说开销的问题,有些时候我们需要做一些自定义的输出,与log系统进行结合,可是e.printStackTrace();
并没有返回值,这就很尴尬,接下来我们自定义异常收集器
三.自定义异常收集器
3.1 定义log输出的模板
设计的理念:
1.我们采用模板的设计模式定义接口,如果小伙伴对模板模式不了接,请看这篇文章https://blog.csdn.net/weixin_38937840/article/details/104211816
2.我们获取堆里的异常信息(当然获取Throwable ,Exception也是可以),源码在文末会提供
public abstract class LogTemplate {
/**前缀*/
protected static final String PREFIX = "Java有货";
/**链接符*/
protected static final String JOINER = "-----";
/**
* <p>
* 自定义前缀输出
* </p>
* /
protected abstract void logError(String prefix,StackTraceElement[] stackTrace);
/**
* <p>
* 默认前缀统一输出
* </p>
*/
protected abstract void logError(StackTraceElement[] stackTrace);
// protected abstract void logError(String prefix, Exception e);
// protected abstract void logError(Exception e);
// protected abstract void logError(String prefix, Throwable e);
// protected abstract void logError(Throwable e);
protected boolean verify(String prefix){
boolean blank = StringUtils.isEmpty(prefix);
return blank;
}
/**
* 统一日志出口
*/
public void logPrint(String prefix, StackTraceElement[] stackTrace){
boolean verify = verify(prefix);
if (verify){
logError(stackTrace);
}else {
logError(prefix,stackTrace);
}
}
3.2 实现自定义输出
@Slf4j
public class LogError extends LogTemplate {
@Autowired(required = false)
private TaskExecutor taskExecutor;
private static final String MSG = " 错误详细信息 : ";
/**
* <p>
* 错误日志记录
* </p>
*/
@Override
protected void logError(String prefix,StackTraceElement[] stackTrace) {
log(prefix ,stackTrace );
}
/**
* <p>
* 错误日志记录
* </p>
*/
@Override
protected void logError(StackTraceElement[] stackTrace) {
log(stackTrace);
}
/**
* <p>
* 错误日志记录,内部输出
* </p>
*/
private void log(String prefix,StackTraceElement[] stackTrace){
CompletableFuture.runAsync(() -> {
for (StackTraceElement stackTraceElement : stackTrace) {
log.error(PREFIX + JOINER + prefix.trim() + JOINER + "{}",MSG+ stackTraceElement.toString());
}
},taskExecutor);
}
/**
* <p>
* 错误日志记录,内部输出
* </p>
*/
private void log(StackTraceElement[] stackTrace){
CompletableFuture.runAsync(() -> {
for (StackTraceElement stackTraceElement : stackTrace) {
log.error(PREFIX + "{}", JOINER +MSG+ stackTraceElement);
}
},taskExecutor);
}
}
这里使用了CompletableFuture,如果不了解的同学,请看下面的文章
https://blog.csdn.net/weixin_38937840/article/details/105046588
3.3 使用验证
try {
Integer.valueOf("22m");
} catch (NumberFormatException e) {
logError.logPrint("swagger",e.getStackTrace());
}
如下图,这时我们就可以与业务场景进行高度结合,快速定位
源码地址:https://github.com/Dylan-haiji/javayh-platform/tree/master/javayh-starter/javayh-log-starter/src/main/java/com/javayh/log/log
本文的分享暂时就到这里,希望对您有所帮助
关注 Java有货领取更多资料
联系小编。微信:372787553,带您进群互相学习
左侧小编微信,右侧获取免费资料
- SpringCloud 自定义封装架构https://github.com/Dylan-haiji/javayh-platform
- Java 设计模式学习代码 https://github.com/Dylan-haiji/design-pattern
- SpringCloud学习代码: https://github.com/Dylan-haiji/javayh-cloud
- AlibabaCloud学习代码:https://github.com/Dylan-haiji/javayh-cloud-nacos
- SpringBoot+Mybatis 多数据源切换:https://github.com/Dylan-haiji/javayh-boot-data-soure
- Redis、Mongo、Rabbitmq、Kafka学习代码: https://github.com/Dylan-haiji/javayh-middleware
- SpringBoot+SpringSecurity实现自定义登录学习代码:https://github.com/Dylan-haiji/javayh-distribution