exception与error的区别(关于error和exception)

健康新闻 2023-05-01 18:58健康生活www.xingbingw.cn

  exception与error的区别(关于error和exception),新营销网红网本栏目通过数据整理汇集了exception与error的区别(关于error和exception)相关信息,下面一起看看。

   Java中的基本思想是,结构不良的代码是无法运行的,发现错误的理想时间是在编译过程中,因为你不用运行程序,但是只要理解Java的基本思想就可以发现问题。然而,编译时并不能找出所有的问题。有一些NullPointerException和ClassNotFoundException在编译时找不到。这些异常是RuntimeException运行时异常,这些异常通常只能在运行时发现。

  我们在编写Java程序的时候经常会遇到两种问题,一种是java.lang.Exception,一种是java.lang.Error,这两种都是用来表示异常情况的。下面是对这两个概念的理解。

  知道ExceptionException位于java.lang包下。这是一个顶级接口,继承自Throwable类。异常类及其子类是Throwable的组成部分,这是程序出现的合理情况。

  在知道异常之前,有必要知道什么是Throwable。

   ThrowableThrowable类是Java语言中所有错误和异常的父类。只有继承自Throwable或其子类的类才能被抛出。另一种方式是Java中带有@throw注释的类也可以抛出。

  在Java规范中,未检查异常和已检查异常的定义如下:

  未检查的异常类是运行时异常类和错误类。

  选中的异常类是除未选中异常类之外的所有异常类。也就是说,被检查的异常类是Throwable及其所有子类,而不是RuntimeException及其子类和Errorand及其子类。

  也就是说,除了RuntimeException及其子类,error及其子类,其他所有异常都是checkedException。

  然后,根据这个逻辑关系,我们可以对Throwable及其子类进行分类分析。

  如您所见,Throwable位于异常和错误的顶端。当我们看Throwable类时,我们发现Throwable有许多and属性,我们将只讨论其中常用的几个。

   //返回抛出异常publicstringgetMessage()的详细信息;publicstringgetlocalized message();//返回异常发生时的简短描述:publicstringtostring();//将异常信息打印到标准输出流publicvidprintstacktrace();publicvidprintstacktrace(PrintStreams);publicvidprintstacktrace(printwriters)//记录堆栈帧的当前状态public synchronized ThrowableFillInstackTrace();另外,因为Throwable的父类也是Object,所以常用继承其父类的getClass()和getName()。

  常见异常让我们回到异常的讨论上来。现在你知道Exception的父类是Throwable,有两种异常,一种是运行时异常;一个是CheckedException,两个异常都应该被捕获。

  下面是Java中一些常见的异常及其分类。这位面试官可能还会让你说出几个常见的例外,并进行分类。

  运行时异常

  取消检查异常

  与异常相关的Java关键字。那么Java是如何处理这些异常的呢?Java里有这些关键词:throws,throw,try,finally,catch。我们分别讨论一下。

  抛出和抛出在Java中,异常也是一个对象,可以由程序员抛出,也可以由应用程序抛出。必须使用Throws和throws语句来定义引发的异常。

  抛出和抛出通常成对出现,例如

   staticvoidcacheException()throws exception { thrownewException();}throw语句用在正文中,表示抛出异常,由正文中的语句处理。Throws语句用在声明之后,表示将再次引发异常,该异常将由该语句的调用方处理。

   Throws主要声明这将抛出这种类型的异常,这样它的调用者就知道要捕捉这个异常。Throw是向外抛出异常的具体动作,所以它抛出的是一个异常实例。

  尝试、发现

  ally 、catch

  这三个关键字主要有下面几种组合方式try...catch 、try...finally、try...catch...finally。

  try...catch 表示对某一段代码可能抛出异常进行的捕获,如下

  staticvoidcacheException()throwsException{try{System.out.println( 1 }catch(Exceptione){e.printStackTrace();}}

  try...finally 表示对一段代码不管执行情况如何,都会走 finally 中的代码

  staticvoidcacheException()throwsException{for(inti=0;i 5;i++){System.out.println( enter:i= +i);try{System.out.println( execute:i= +i);continue;}finally{System.out.println( leave:i= +i);}}}

  try...catch...finally 也是一样的,表示对异常捕获后,再走 finally 中的代码逻辑。

  JDK1.7 使用 try...with...resources 优雅关闭资源

  Java 类库中有许多资源需要通过 close 进行关闭。比如 InputStream、OutputStream,数据库连接对象 Connection,MyBatis 中的 SqlSession 会话等。作为开发人员经常会忽略掉资源的关闭 ,导致内存泄漏。

  根据经验,try-finally语句是确保资源会被关闭的最佳 ,就算异常或者返回也一样。try-catch-finally 一般是这样来用的

  staticStringfirstLineOfFile(Stringpath)throwsIOException{BufferedReaderbr=newBufferedReader(newFileReader(path));try{returnbr.readLine();}finally{br.close();}}

  这样看起来代码还是比较整洁,但是当我们添加第二个需要关闭的资源的时候,就像下面这样

  staticvoidcopy(Stringsrc,Stringdst)throwsException{InputStreamis=newFileInputStream(src);try{OutputStreamos=newFileOutputStream(dst);try{byte[]buf=newbyte[100];intn;while((n=is.read()) =0){os.write(buf,n,0);}}finally{os.close();}}finally{is.close();}}

  这样感觉这个 已经变得臃肿起来了。

  而且这种写法也存在诸多问题,即使 try - finally 能够正确关闭资源,但是它不能阻止异常的抛出,因为 try 和 finally 块中都可能有异常的发生。

  比如说你正在读取的时候硬盘损坏,这个时候你就无法读取文件和关闭资源了,此时会抛出两个异常。但是在这种情况下,第二个异常会抹掉第一个异常。在异常堆栈中也无法找到第一个异常的记录,怎么办,难道像这样来捕捉异常么?

  staticvoidtryThrowException(Stringpath)throwsException{BufferedReaderbr=newBufferedReader(newFileReader(path));try{Strings=br.readLine();System.out.println( s= +s);}catch(Exceptione){e.printStackTrace();}finally{try{br.close();}catch(Exceptione){e.printStackTrace();}finally{br.close();}}}

  这种写法,虽然能解决异常抛出的问题,但是各种 try-cath-finally 的嵌套会让代码变得非常臃肿。

  Java7 中引入了try-with-resources 语句时,所有这些问题都能得到解决。要使用 try-with-resources 语句,首先要实现 AutoCloseable 接口,此接口包含了单个返回的 close 。Java 类库与三方类库中的许多类和接口,现在都实现或者扩展了 AutoCloseable 接口。如果编写了一个类,它代表的是必须关闭的资源,那么这个类应该实现 AutoCloseable 接口。

  java 引入了 try-with-resources 声明,将 try-catch-finally 简化为 try-catch,这其实是一种语法糖,在编译时会进行转化为 try-catch-finally 语句。

  下面是使用 try-with-resources 的第一个范例

  /***使用try-with-resources改写示例一*@parampath*@return*@throwsIOException*/staticStringfirstLineOfFileAutoClose(Stringpath)throwsIOException{try(BufferedReaderbr=newBufferedReader(newFileReader(path))){returnbr.readLine();}}

  使用 try-with-resources 改写程序的第二个示例

  staticvoidcopyAutoClose(Stringsrc,Stringdst)throwsIOException{try(InputStreamin=newFileInputStream(src);OutputStreamos=newFileOutputStream(dst)){byte[]buf=newbyte[1000];intn;while((n=in.read(buf)) =0){os.write(buf,0,n);}}}

  使用 try-with-resources 不仅使代码变得通俗易懂,也更容易诊断。以firstLineOfFileAutoClose 为例,如果调用 readLine() 和 close() 都抛出异常,后一个异常就会被禁止,以保留第一个异常。

  异常处理的原则

  我们在日常处理异常的代码中,应该遵循三个原则

  不要捕获类似 Exception 之类的异常,而应该捕获类似特定的异常,比如 InterruptedException,方便排查问题,而且也能够让其他人接手你的代码时,会减少骂你的次数。

  不要生吞异常。这是异常处理中要特别注重的事情,因为很可能会非常难以正常结束情况。如果我们不把异常抛出来,或者也没有输出到 Logger 日志中,程序可能会在后面以不可控的方式结束。

  不要在函数式编程中使用 checkedException。

  什么是 Error

  Error 是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。这些错误是不可检查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况,比如 OutOfMemoryError 和 StackOverflowError异常的出现会有几种情况,这里需要先介绍一下 Java 内存模型 JDK1.7。

  其中包括两部分,由所有线程共享的数据区和线程隔离的数据区组成,在上面的 Java 内存模型中,只有程序计数器是不会发生 OutOfMemoryError 情况的区域,程序计数器控制着计算机指令的分支、循环、跳转、异常处理和线程恢复,并且程序计数器是每个线程私有的。

  什么是线程私有:表示的就是各条线程之间互不影响,独立存储的内存区域。

  如果应用程序执行的是 Java ,那么这个计数器记录的就是虚拟机字节码指令的地址;如果正在执行的是 Native ,这个计数器值则为空(Undefined)。

  除了程序计数器外,其他区域: 区(Method Area)、虚拟机栈(VM Stack)、本地 栈(Native Method Stack) 和 堆(Heap) 都是可能发生 OutOfMemoryError 的区域。

  虚拟机栈:如果线程请求的栈深度大于虚拟机栈所允许的深度,将会出现 StackOverflowError 异常;如果虚拟机动态扩展无法申请到足够的内存,将出现 OutOfMemoryError。

  本地 栈和虚拟机栈一样

  堆:Java 堆可以处于物理上不连续,逻辑上连续,就像我们的磁盘空间一样,如果堆中没有内存完成实例分配,并且堆无法扩展时,将会抛出 OutOfMemoryError。

   区: 区无法满足内存分配需求时,将抛出 OutOfMemoryError 异常。

  一道经典的面试题

  一道非常经典的面试题,NoClassDefFoundError 和 ClassNotFoundException 有什么区别?

  在类的加载过程中, JVM 或者 ClassLoader 无法找到对应的类时,都可能会引起这两种异常/错误,由于不同的 ClassLoader 会从不同的地方加载类,有时是错误的 CLASSPATH 类路径导致的这类错误,有时是某个库的 jar 包缺失引发这类错误。NoClassDefFoundError 表示这个类在编译时期存在,但是在运行时却找不到此类,有时静态初始化块也会导致 NoClassDefFoundError 错误。

  ClassLoader 是类路径装载器,在Java 中,类路径装载器一共有三种两类

  一种是虚拟机自带的 ClassLoader,分为三种

  启动类加载器(Bootstrap) ,负责加载 $JAVAHOME/jre/lib/rt.jar扩展类加载器(Extension),负责加载 $JAVAHOME/jre/lib/ext/*.jar应用程序类加载器(AppClassLoader),加载当前应用的 classpath 的所有类

  第二种是用户自定义类加载器

  Java.lang.ClassLoader 的子类,用户可以定制类的加载方式。

  另一方面,ClassNotFoundException 与编译时期无关,当你尝试在运行时使用反射加载类时,ClassNotFoundException 就会出现。

  简而言之,ClassNotFoundException 和 NoClassDefFoundError 都是由 CLASSPATH 中缺少类引起的,通常是由于缺少 JAR 文件而引起的,但是如果 JVM 认为应用运行时找不到相应的引用,就会抛出 NoClassDefFoundError 错误;当你在代码中显示的加载类比如 Class.forName() 调用时却没有找到相应的类,就会抛出java.lang.ClassNotFoundException。

  NoClassDefFoundError 是 JVM 引起的错误,是 unchecked,未经检查的。因此不会使用 try-catch 或者 finally 语句块;另外,ClassNotFoundException 是受检异常,因此需要 try-catch 语句块或者 try-finally 语句块包围,否则会导致编译错误。

  调用Class.forName()、ClassLoader.findClass() 和 ClassLoader.loadClass()等 时可能会引起 java.lang.ClassNotFoundException,如图所示

  NoClassDefFoundError 是链接错误,发生在链接阶段,当解析引用找不到对应的类,就会触发;而 ClassNotFoundException 是发生在运行时的异常。

  文章参考:

  https://www.java67.com/2012/12/noclassdeffounderror-vs-classnotfoundexception-java.html

  《极客时间-Java核心技术 36 讲》

  《深入理解 Java 虚拟机》第二版

  《Effective Java 第三版》

  https://www.cnblogs.com/xiohao/p/3547443.html

  https://blog.csdn.net/qq_29229567/article/details/80773970

  https://blog.csdn.net/riemann_/article/details/87522352

  《Java编程思想》

  https://www.cnblogs.com/xz816111/p/8466048.html

  https://docs.oracle.com/javase/specs/jls/se9/html/jls-11.html#jls-11.1.1

  jdk 1.8 源码注释

  error

  更多exception与error的区别(关于error和exception)相关信息请关注本文章,本文仅仅做为展示!

Copyright@2015-2025 www.xingbingw.cn 性病网版板所有