优秀的编程知识分享平台

网站首页 > 技术文章 正文

谈谈我对Exception和Error的理解(未完)

nanyue 2024-10-02 17:42:59 技术文章 10 ℃

摘要: NoClassDefFoundError/ClassNotFoundException NoClassDefFoundError发生在jvm运行时,执行某个方法或者静态成员时,如果jvm加载不到该类时报错的错误。

私信“555”可获取架构资料,与大牛一起交流~~

NoClassDefFoundError/ClassNotFoundException

NoClassDefFoundError发生在jvm运行时,执行某个方法或者静态成员时,如果jvm加载不到该类时报错的错误。本地编译没报错,但运行时报错,有可能该类对类加载器而言是不可见的。

ClassNotFoundException发生与编译时根据classpath找不到对应类时报的错误。

由于User类为"private"修饰,Test.java里的main无权访问,编译时不会报错到运行时因找到User类NotClassDefFoundError:

import java.util.ArrayList;
import java.util.List;
/**
 * Created by fujianbo on 2018/5/12.
 *
 * @author fujianbo
 * @date 2018/05/12
 */
public class Test {
 public static void main(String args[]){
 List<User> users = new ArrayList<>(2);
 try {
 users.add(new User("1234"));
 } catch (Throwable t) {
 t.printStackTrace();
 }
 }
}
class User{
 private static String USER_ID = getUserId();
 public User(String id){
 this.USER_ID = id;
 }
 private static String getUserId() {
 throw new RuntimeException("UserId Not found");
 }
}

不良案例

捕获时异常要明确异常类型,提高代码可读性

public class Test {
 public static void main(String args[]){
 try {
 Thread thread = new Thread();
 // do something
 // ...
 thread.wait();
 } catch (InterruptedException e) {
 
 }
 }
}

捕获异常范围不宜过大

RuntimeException更应该扩散而不是捕获(很多时候我们并不能处理这类异常),如Throwable或则Error也是如此。

不要使用标准输出打印异常

try {
 Thread thread = new Thread();
 // do something
 // ...
 thread.wait();
 } catch (InterruptedException e) {
 e.printStackTrace();
}

使用e.printStackTrace将导致异常堆栈输出到标准异常流,这很难判断日志最终被输出都哪里而丧失监控的意义。

throw early & catch late原则

public static void main(String args[]){
 loadFile(null);
 }
 private static void loadFile(String fileName) {
 try {
 FileInputStream fileInputStream = new FileInputStream(fileName);
 func1(fileInputStream);
 func2(fileInputStream);
 } catch (FileNotFoundException e) {
 // take logs here
 }
 }
 
 private static void func1(FileInputStream fileInputStream) {
 if (fileInputStream == null) {
 return;
 }
 // do something
 }
 
 private static void func2(FileInputStream fileInputStream) {
 // do something
 }

throw early可节省查看堆栈排查问题的时间,无论使用断言还是if判断都可以简单做到。

自定义异常

  • Checked Exception的初衷为从异常中恢复,哪些要恢复以及怎么恢复依赖于精细化的异常分类
  • 异常信息不要包含敏感信息,这是ConnectionException不打印ip和端口信息的原因

Checked Exception Or Unchecked Exception?

  • [引用自某博客,出处后续补上]虽然反对使用Checked Exception的声音不少,但Checked Exception在提示不要忘记处理异常,虽然调用该方法的方法体需要申明外抛异常,但至少可以指导底层会抛哪些异常,在自定义异常时提供了有效信息(异常种类划分&处理)
  • Unchecked Exception使代码更简洁,但容易丢失详细堆栈信息。如调用链路横跨多个流程,每个流程涉及到的方法调用都有上下文,哪一步出错可以依赖不同流程的上下文打印信息,快速定位问题。
  • try/catch代码块产生额外的性能开销,影响jvm优化(尽量缩小try/catch块的大小)
  • 实例化一个Exception会保留执行时的堆栈快照,该过程为相对较重的操作。

思考

Reactive Stream(异步、基于事件机制),出现异常不能简单外抛。由于代码堆栈不在是同步调用时的垂直结构,我们看到的是特定executor的堆栈。那如何处理这类异常呢?(未完待续...)私信“555”可获取架构资料,与大牛一起交流~~

最近发表
标签列表