compilation error错误是什么原因_Java专题讲解——Java错误处理机制

世界上并不存在不会出错的系统,只要是软件系统就一定会在运行的过程中出现开发人员无法预料的错误。如何处理意外发生就是我们作为一名开发人员所必须深入思考的问题。

Java语言提供了完善的异常处理机制,它有效的降低了编写以及维护的门槛(这也是Java语言大行其道的原因,好上手,机制全)。今天在这里和大家分享一下Java异常机制的特点以及应用。

现在我们回想一下,在日常开发中我们常常用到try……catch……语句,比如写一个文件输入输出流,此时我们必须catch相应的IOException、FileNotFountException,否则编译不通过,那这里catch的是什么东西?答案是“Exception”。那平时我们在系统运行中发现系统崩溃,比如OutOfMemoryError错误,那这个OOM是什么东西?答案是“Error”。综上所述,Java中的异常分为两大类Exception和Error,它们都集成了Throwable类(只有集成了Throwable类才能被抛出或者捕获)。

Error是指正常情况下不大可能出现的情况,一旦出现很有可能导致程序处于不可恢复的非正常状态,开发人员不便于也不需要捕获。Exception则可以分为checked和unchecked异常,checked表示必须显示捕获处理,否则编译不通过。


重点问题:NoClassDefFoundError和ClassNotFoundException有什么区别?

NoClassDefFoundError是一个错误(Error),而ClassNotFoundException是一个异常(Exception),我们应该尝试从异常中恢复程序,而不应该尝试从错误中恢复程序。

  • ClassNotFoundException

ClassNotFoundException是一个checkedException,需要显示捕获处理。

ClassNotFoundException产生的原因是:Java使用Class.forName方法动态加载类到JVM内存中,但是如果传递的类在类路径中没有被找到,那么就会抛出ClassNotFoundException异常。ClassLoader.loadClass,ClassLoader.findSystemClass等方法在动态加载类到内存中的时候也可能会跑出去这个异常。

还有一种导致ClassNotFoundException发生的原因,当一个类已经被某个类加载器加载到内存中了,此时另一个类加载器又尝试动态从同一个包中加载这个类。此时也会出现ClassNotFoundException异常。

Demo:

public 

报如下错误:

493781ca8e093ec3dde1fb5f87fabeab.png
  • NoClassDefFoundError

NoClassDefFoundError产生的原因是:JVM或者ClassLoader实例尝试加载类的时候找不到类的定义。它是一个LlinkageError,LinkageError发生的情况是在一个类依赖另一个类,而后者在前者编译后又发生了改变。导致出现LinkageError的错误。

Demo:

class GeeksForGeeks  
{
    void greeting()
    {
        System.out.println("hello!");
    }
}class G4G {
    public static void main(String args[])  
    {
        GeeksForGeeks geeks = new GeeksForGeeks();
        geeks.greeting();
    }
}


分别使用javac编译两个文件,然后使用java G4G运行。当我们把编译后的GeeksForGeeks.class文件拿走后,就会报NoClassDefFoundError的错误。

022b9aa47c54582ab88c3c1c5f71588e.png


NoClassDefFoundError无法显示捕获,出现在创建对象调用方法的过程中。

ClassNotFoundException必须显示捕获,出现在Class.forName等方法中。


通过上面的描述我们理解了Error和Exception之间的区别,接下来我们需要理解Java语言是如何操作Throwable元素。基本的语法包括“try-catch-finally”,“throw”,“throws”,“try-with-resources”等。异常处理有几个原则需要遵守:

(1)尽量不要捕获类似Exception这样的通用异常,而应该捕获特定异常。

(2)不要生吞异常。注意不要在生产环境使用e.printStackTrace()打印异常,最好使用产品日志,详细输出到日志系统。

(3)Throw early, catch late。提前把异常抛出来,或者构建新的异常抛出去。这里就涉及到自定义异常,需要确定是否需要自定义checked Exception;在保证诊断信息的同事避免敏感信息,比如java.net.ConnectException的出错信息不包括机器名、IP、端口等敏感信息。

有一种说法,提出Java语言的checkedException是一种设计错误。因为checkedException的初衷是希望捕获异常,再从异常中回复正常,但是大多数情况不能恢复。另外checkedException不兼容functional编程,比如Lambda/Stream代码。

但也有一部分人提出,确实有一些异常是可恢复的,比如IO异常、网络异常等。


那么接下来我们从性能的角度来审视Java的异常处理机制。

  • 首先try-catch代码会影响JVM对代码的优化,所以不要用try包裹大段的代码。
  • 另外不要试图用异常捕获来控制代码流程,比起if/else之类的语句,异常捕获要更加低效。
  • 最后Java实例化Exception都会对当时的栈进行快照,该操作较重。对于追求极致性能的底层类库,创建不进行栈快照的Exception是一种方法。但是这样不利于我们定位问题,特别是在微服务这样的分布式系统,会增加诊断的难度。当服务变慢,吞度量下降时,检查最频繁的Exception是一种思路。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值