Java语言在设计之初就提供了相对完善的异常处理机制,这也是Java得以大行其道的原因之一,因为这种机制大大降低了编写和维护可靠程序的门槛。

本文参照:极客时间-《java核心技术36讲》-第二讲

Throwable

Exception和Error都是继承了Throwable类,在Java中只有Throwable类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。

java writer错误 java error_类加载机制

Exception和Error的区别

Exception和Error体现了Java平台设计者对不同异常情况的分类。Exception是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
Error是指在正常情况下,不大可能出现的情况,绝大部分的Error都会导致程序(比如JVM自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如OutOfMemoryError之类,都是Error的子类。

总结就是:
1.Error:系统错误,虚拟机出错,我们处理不了,也不需要我们来处理。
2.Exception,可以捕获的异常,且作出处理。也就是要么捕获异常并作出处理,要么继续抛出异常。

运行时异常与一般异常的区别

Exception又分为可检查(checked)异常和不检查(unchecked)异常,可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。

不检查异常就是所谓的运行时异常,类似 NullPointerException、ArrayIndexOutOfBoundsException之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。

NoClassDefFoundError和ClassNotFoundException有什么区别

NoClassDefFoundError是一个错误(Error),而ClassNOtFoundException是一个异常,在Java中对于错误和异常的处理是不同的,我们可以从异常中恢复程序但却不应该尝试从错误中恢复程序。

ClassNotFoundException的产生原因:
Java支持使用反射方式在运行时动态加载类,例如使用Class.forName方法来动态地加载类时,可以将类名作为参数传递给上述方法从而将指定类加载到JVM内存中,如果这个类在类路径中没有被找到,那么此时就会在运行时抛出ClassNotFoundException异常。

解决该问题需要确保所需的类连同它依赖的包存在于类路径中,常见问题在于类名书写错误。

另外还有一个导致ClassNotFoundException的原因就是:当一个类已经某个类加载器加载到内存中了,此时另一个类加载器又尝试着动态地从同一个包中加载这个类。通过控制动态类加载过程,可以避免上述情况发生。

NoClassDefFoundError产生的原因在于:
如果JVM或者ClassLoader实例尝试加载(可以通过正常的方法调用,也可能是使用new来创建新的对象)类的时候却找不到类的定义。要查找的类在编译的时候是存在的,运行的时候却找不到了。这个时候就会导致NoClassDefFoundError。

造成该问题的原因可能是打包过程漏掉了部分类,或者jar包出现损坏或者篡改。解决这个问题的办法是查找那些在开发期间存在于类路径下但在运行期间却不在类路径下的类。

java writer错误 java error_java writer错误_02

综上,分析类的加载机制,加载时从外存储器找不到需要的class就出现ClassNotFoundException;连接时从内存找不到需要的class就出现NoClassDefFoundError。

try-catch-fnally

throw、throws关键字

使用建议

  1. 尽量不要捕获类似Exception这样的通用异常,而是应该捕获特定异常。我们有义务让自己的代码能够直观地体现出尽量多的信息,而泛泛的Exception之类,恰恰隐藏了我们的目的。另外,我们也要保证程序不会捕获到我们不希望捕获的异常。比如,你可能更希望RuntimeException被扩散出来,而不是被捕获。
    进一步讲,除非深思熟虑了,否则不要捕获Throwable或者Error,这样很难保证我们能够正确程序处理OutOfMemoryError。
  2. 不要生吞(swallow)异常。生吞异常,往往是基于假设这段代码可能不会发生,或者感觉忽略异常是无所谓的,但是千万不要在产品代码做这种假设!如果我们不把异常抛出来,或者也没有输出到日志(Logger)之类,程序可能在后续代码以不可控的方式结束。
  3. 尽量不要一个大的try包住整段的代码。try-catch代码段会产生额外的性能开销,或者换个角度说,它往往会影响JVM对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的try包住整段的代码;与此同时,利用异常控制代码流程,也不是一个好主意,远比我们通常意义上的条件语句(if/else、switch)要低效。
  4. 异常的开销。Java每实例化一个Exception,都会对当时的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略了。
  5. 不要在fnally代码块中处理返回值。按照我们程序员的惯性认知:当遇到return语句的时候,执行函数会立刻返回。但是,在Java语言中,如果存在fnally就会有例外。除了return语句,try代码块中的break或continue语句,也可能使控制权进入fnally代码块。
  6. 请勿在try代码块中调用return、break或continue语句。万一无法避免,一定要确保fnally的存在不会改变函数的返回值。