day3的分享,从标题我们也知道,这是java基础。但是有时候,老兵跟新兵蛋子的区别往往就是在最简单基础之处。
java异常体系 异常的作用- 描述导致当前异常发生的原因
- 根据异常栈快速定位到导致当前异常发生的位置
在日常工作中,尤其是在处理生产问题时,结合异常描述和异常栈,定位分析解决异常,是非常常用且有效的手段。
java异常处理流程往简单了说,就是先看是否存在try-catch-finally,没有就由JVM处理了。
而想要看懂这个图,关键点在右下角的是否已处理。这里的是否已处理,表示的是,如果异常已被catch命中,那就是已处理,如果没有命中,那就是还没有处理。换而言之,就是与前面的catch分支处理有所关联。
- java异常处理机制
try-catch-finally直接处理异常
throws在当前方法中不处理,直接通过throw向上抛出。
有意思的是,try-catch-finally块在对流对象的处理上,随着jdk版本的发布有了新的处理姿势。但注意,得是实现了java.lang.AutoCloseable接口才行。有兴趣的同学可以自行了解。
敲黑板,小白同学要认真点哈。如果我们都搞不清楚java有哪些异常,我们要怎么用好异常呢?
注:黄色框表示的是例子,并不是只有这些。
这里解释一下,受检查异常与非受检查异常。
- 非受检查异常
- 继承于RumtimeException
- 在代码中不会强制捕获
- 我们碰到最多的是此类异常,例如空指针异常、类型转换异常、下标越界异常等等。
- 受检查异常
- 直接继承于Exception
- 在代码中如果调用方法声明thows的异常是非受检查异常,则会强制必须捕获,否则无法编译。
在定义业务异常时,以前的我可能会定义为受检查异常,但现在,我更倾向于定义为非受检查异常。首先,业务异常通常都会有对应的错误码和错误信息,一般情况下,都是直接抛出到用户界面类提示用户的。基于此原因,没有必要强制开发人员进行捕获。一来,使得代码变得复杂。二来,不容易直观的阅读核心处理逻辑。至于,如何给用户界面响应,如果你用的是Spring,可以直接定义个全局异常处理器就好。
异常处理规约 异常处理原则- 非必要不使用异常
- 使用描述性消息抛出异常
- 力所能及的异常一定要处理
- 异常忽略应当有理有据
相信大家对于NPE也是很厌烦的,因为if判断写起来没完了,尤其是在属性嵌套的情况下,不可避免的需要嵌套if来判断。多亏了JDK8,为我们带来了Optional.来看看他是怎么简化的。
// 定义一个带嵌套对象的对象
Test test = new Test();
test.setA(new A());
test.getA().setAa(new A());
// 新姿势获取最内层的aa对象
A weizhi = Optional.ofNullable(test)
// 获取一级对象中的二级属性
.map(t -> t.getA())
// 获取二级对象中的属性
.map(a -> a.getAa())
// 只要任意一层级属性为空,则返回默认值(这里是直接新建一个)
// .orElseGet(() -> new A());
// 只要存在空指针就转换异常并抛出
.orElseThrow(() -> new RuntimeException("WEIZHI"));
特殊场景的异常处理对策
foreach循环遍历集合异常
- 不要在循环中对当前遍历的集合进行remove/add操作
- 需要先确保集合不为空,否则会抛出NPE。即学即用,优雅判空,上代码:
Optional.ofNullable(a)
.orElse(Collections.emptyList())
.stream()
.forEach(System.out::println);
当然,直接判空提前结束执行,也是可以的。
- 对于集合中可能存在的空元素,也应当处理一下。
- 集合遍历过程中可能发生的异常,应当跟实际业务进行处理。是直接结束,还是忽略跳过继续执行下一个元素。



