原创

10.Java异常问题


目录介绍

  • 10.0.0.1 见过哪些运行时异常?异常处理机制知道哪些?从异常是否必须需要被处理的角度来看怎么分类?
  • 10.0.0.2 运用Java异常处理机制?异常处理的原理?Java中检查异常和非检查异常的区别?
  • 10.0.0.3 异常处理的过程中,你遵循那些好的实践? throw 和 throws这两个关键字在java中有什么不同?
  • 10.0.0.4 你知道什么是“异常链”吗?自定义实现过哪些异常,怎么写的?可以有一个空的catch块吗?
  • 10.0.0.5 Java异常类有哪些的重要方法?导致“主线程中的异常”的不同场景是什么?
  • 10.0.0.6 看下面这段子类继承父类代码有什么问题?针对抛异常是IOException还是Exception,能随便写吗,结合案例说一下?
  • 10.0.0.7 捕获异常时,为何在catch中要注意异常层级关系?需要注意哪些问题?
  • 10.0.0.8 在程序中使用自定义异常类,大体可分为哪些步骤?哪些开发场景用到,说说你的编程经验?
  • 10.0.0.9 平时遇到的OOM可以被try-catch吗?如果要catch OOM需要什么先决条件?是否建议catch住OOM,为什么?

好消息

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计500篇[近100万字],将会陆续发表到网上,转载请注明出处,谢谢!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!所有博客将陆续开源到GitHub!

10.0.0.1 见过哪些运行时异常?异常处理机制知道哪些?从异常是否必须需要被处理的角度来看怎么分类?

  • 运行时异常:Throwable继承层次结构,可见分成两大类Error和Exception:
    • Error(错误):指程序无法恢复的异常情况,表示运行应用程序中较严重的问题;发生于虚拟机自身、或者在虚拟机试图执行应用时,如Virtual MachineError(Java虚拟机运行错误)、NoClassDefFoundError(类定义错误);属于不可查异常,即不强制程序员必须处理,即使不处理也不会出现语法错误。
    • Exception(异常):指程序有可能恢复的异常情况,表示程序本身可以处理的异常。又分两大类:
      • RuntimeException(运行时异常):由程序自身的问题导致产生的异常;如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常);属于不可查异常。
      • 非运行时异常:由程序外部的问题引起的异常;除了RuntimeException以外的异常,如FileNotFoundException(文件不存在异常);属于可查异常,即强制程序员必须进行处理,如果不进行处理则会出现语法错误。
  • 异常处理机制
    • 捕捉异常:由系统自动抛出异常,即try捕获异常->catch处理异常->finally 最终处理
    • 抛出异常:在方法中将异常对象显性地抛出,之后异常会沿着调用层次向上抛出,交由调用它的方法来处理。配合throws声明抛出的异常和throw抛出异常
    • 自定义异常:继承Execption类或其子类
    • 技术博客大总结
  • 从异常是否必须需要被处理的角度来看怎么分类
    • 异常又可分为不受检查异常和受检查异常两种情况:
      • 不受检查异常:派生于 Error 或 RuntimeException 的所有异常;
      • 受检查异常:除去不受检查异常的所有异常。
      • image

10.0.0.2 运用Java异常处理机制? 异常处理的原理?Java中检查异常和非检查异常的区别?

  • 运用Java异常处理机制?
    • 1.try…catch语句
    • 2.finally语句:大多数情况下都必须执行的代码
    • 3.throws子句:声明可能发生的异常类
    • 4.throw:抛出具体的异常对象。
  • 异常处理的原理?
    • Java虚拟机用方法调用栈(method invocation stack)来跟踪每个线程中一系列的方法调用过程。如果在执行方法过程中抛出异常,则Java虚拟机必须找到能捕获该异常的catch代码块。当Java虚拟机追溯到调用栈的底部的方法的时候,如果仍然没有找到处理该异常的代码块,这样它就会按步骤处理,首先会打印方法调用栈的异常信息,然后如果所处的线程不是主线程,那么就会终止这个线程。
  • Java中检查异常和非检查异常的区别
    • 检查型异常(CheckedException)
      • 在Java中所有不是RuntimeException派生的Exception都是检查型异常。当函数中存在抛出检查型异常的操作时该函数的函数声明中必须包含throws语句。调用改函数的函数也必须对该异常进行处理,如不进行处理则必须在调用函数上声明throws语句。
      • 检查型异常是JAVA首创的,在编译期对异常的处理有强制性的要求。在JDK代码中大量的异常属于检查型异常,包括IOException,SQLException等等。
    • 非检查型异常(UncheckedException)技术博客大总结
      • 在Java中所有RuntimeException的派生类都是非检查型异常,与检查型异常对比,非检查型异常可以不在函数声明中添加throws语句,调用函数上也不需要强制处理。
      • 常见的NullPointException,ClassCastException是常见的非检查型异常。非检查型异常可以不使用try…catch进行处理,但是如果有异常产生,则异常将由JVM进行处理。对于RuntimeException的子类最好也使用异常处理机制。虽然RuntimeException的异常可以不使用try…catch进行处理,但是如果一旦发生异常,则肯定会导致程序中断执行,所以,为了保证程序再出错后依然可以执行,在开发代码时最好使用try…catch的异常处理机制进行处理。

10.0.0.3 异常处理的过程中,你遵循那些好的实践? throw 和 throws这两个关键字在java中有什么不同?

  • 异常处理的过程中,你遵循那些好的实践?
    • 异常处理在项目设计中是非常关键的,所以精通异常处理是十分必要的。异常处理有很多最佳实践,下面列举集中,它们提高你代码的健壮性和灵活性:
      1. 调用方法的时候返回布尔值来代替返回null,这样可以 NullPointerException。由于空指针是java异常里最恶心的异常。
      1. catch块里别不写代码。空catch块是异常处理里的错误事件,因为它只是捕获了异常,却没有任何处理或者提示。通常你起码要打印出异常信息,当然你最好根据需求对异常信息进行处理。
    • 3)能抛受控异常(checked Exception)就尽量不抛受非控异常(checked Exception)。通过去掉重复的异常处理代码,可以提高代码的可读性。
      1. 绝对不要让你的数据库相关异常显示到客户端。由于绝大多数数据库和SQLException异常都是受控异常,在Java中,你应该在DAO层把异常信息处理,然后返回处理过的能让用户看懂并根据异常提示信息改正操作的异常信息。
      1. 在Java中,一定要在数据库连接,数据库查询,流处理后,在finally块中调用close()方法。
  • throw 和 throws这两个关键字在java中有什么不同?
    • 技术博客大总结
    • throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常,你也可以申明未检查的异常,但这不是编译器强制的。如果方法抛出了异常那么调用这个方法的时候就需要将这个异常处理。
    • throw 是用来抛出任意异常的,按照语法你可以抛出任意 Throwable (Throwable 或任何Throwable的衍生类) , throw可以中断程序运行,因此可以用来代替return。
    private static voidshow() {  
        throw new UnsupportedOperationException(“抛出异常”);
    }
    

10.0.0.4 你知道什么是“异常链”吗?自定义实现过哪些异常,怎么写的?可以有一个空的catch块吗?

  • 你知道什么是“异常链”吗?
    • “异常链”是Java中非常流行的异常处理概念,是指在进行一个异常处理时抛出了另外一个异常,由此产生了一个异常链条。该技术大多用于将“ 受检查异常” ( checked exception)封装成为“非受检查异常”(unchecked exception)或者RuntimeException。顺便说一下,如果因为因为异常你决定抛出一个新的异常,你一定要包含原有的异常,这样,处理程序才可以通过getCause()和initCause()方法来访问异常最终的根源。
  • 自定义实现过哪些异常?
  • 可以有一个空的catch块吗?
    • 可以有一个空的catch块,但这是最糟糕的编程的例子。不应该有空的catch块,因为如果异常被该块捕获,我们将没有关于异常的信息,它将成为调试它的噩梦。应该至少有一个日志记录语句来记录控制台或日志文件中的异常详细信息。
    • 技术博客大总结

10.0.0.5 Java异常类有哪些的重要方法?导致“主线程中的异常”的不同场景是什么?

  • Java异常类有哪些的重要方法?
    • Exception和它的所有子类没有提供任何特殊方法供使用,它们的所有方法都是来自其基类Throwable。
      • String getMessage():方法返回Throwable的String型信息,当异常通过构造器创建后可用。
      • String getLocalizedMessage():此方法通过被重写来得到用本地语言表示的异常信息返回给调用程序。Throwable类通常只是用getMessage()方法来实现返回异常信息。
      • synchronized Throwable getCause():此方法返回异常产生的原因,如果不知道原因的话返回null。(原文有拼写错误 应该是if 不是id)
      • String toString():方法返回String格式的Throwable信息,此信息包括Throwable的名字和本地化信息。
      • void printStackTrace():该方法打印栈轨迹信息到标准错误流。该方法能接受PrintStream 和PrintWriter作为参数实现重载,这样就能实现打印栈轨迹到文件或流中。
  • 导致“主线程中的异常”的不同场景是什么?
    • 一些常见的主线程异常情况是:
      • 线程main java.lang.UnsupportedClassVersionError中的异常:当您的java类从另一个JDK版本编译并且您试图从另一个java版本运行它时,会出现此异常。
      • 线程main java.lang.NoClassDefFoundError中的异常 :此异常有两种变体。 第一个是你提供扩展名为.class的类全名的地方。 第二种情况是没有找到类。
      • 线程main java.lang.NoSuchMethodError中的异常:main :当您尝试运行一个没有main方法的类时,会出现此异常。
      • 技术博客大总结
      • 线程“main”中的异常java.lang.ArithmeticException :无论何时从main方法抛出任何异常,它都会打印出异常是console。 第一部分解释了异常从main方法抛出,第二部分打印异常类名称,然后在冒号后打印异常消息。

10.0.0.6 看下面这段子类继承父类代码有什么问题?针对抛异常是IOException还是Exception,能随便写吗,结合案例说一下?

  • 看下面这段代码有什么问题?
    public class SuperClass {  
        public void start() throws IOException{
            throw new IOException("Not able to open file");
        }
    }
    
    public class SubClass extends SuperClass{  
        public void start() throws Exception{
            throw new Exception("Not able to start");
        }
    }
    
    • 这段代码编译器将对子类覆盖start方法产生错误。因为每个Java中方法的覆盖是有规则的,一个覆盖的方法不能抛出的异常比原方法继承关系高。因为这里的start方法在超类中抛出了IOException,所有在子类中的start方法只能抛出要么是IOExcepition或是其子类,但不能是其超类,如Exception。
  • 针对抛异常是IOException还是Exception,能随便写吗,结合案例说一下?
    • 肯定不要随便写,容易造成迷惑性。下面看看代码,举个简单的案例!技术博客大总结
    public static void start(){
       System.out.println("Java Exception");
    }
    
    public static void main(String args[]) {
       try{
          start();
       }catch(IOException e){
          e.printStackTrace();
       }
    }
    
    • 上面的Java异常例子代码中,编译器将在处理IOException时报错,因为IOException是受检查异常,而start方法并没有抛出IOException,所以编译器将抛出“异常,java.io.IOException不会在try语句体中抛出”,但是如果你将IOException改为Exception,编译器报错将消失,因为Exception可以用来捕捉所有运行时异常,这样就不需要声明抛出语句。我喜欢这样带有迷惑性的Java异常面试题,因为它不会让人轻易的找出是IOException还是Exception。你也可以在JoshuaBloach和NeilGafter的Java谜题中找到一些有关Java错误和异常的具有迷惑性问题。

10.0.0.7 捕获异常时,为何在catch中要注意异常层级关系?需要注意哪些问题?

  • 捕获异常时,为何在catch中要注意异常层级关系?需要注意哪些问题?
    • 注意,catch中一定要注意层级关系。这里举一个简单的案例,就可以很好的理解为何要注重层级问题呢!
    • 技术博客大总结
    public static void start() throws IOException, RuntimeException{
        throw new RuntimeException("Not able to Start");
    }
    
    public static void main(String args[]) {
        try {
            start();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (RuntimeException e2) {
            e2.printStackTrace();
        }
    }
    
    • 这段代码会在捕捉异常代码块的RuntimeException类型变量“e2”里抛出编译异常错误。因为Exception是RuntimeException的超类,在start方法中所有的RuntimeException会被第一个捕捉异常块捕捉,这样就无法到达第二个捕捉块,这就是抛出“exception java.lang.RuntimeException has already been caught”的编译错误原因。

10.0.0.9 平时遇到的OOM可以被try-catch吗?如果要catch OOM需要什么先决条件?是否建议catch住OOM,为什么?

  • 正确认识Error和OOM
    • 这里 catch 的是一个 Error,原则上,触发了Error时,它的执行状态已经无法恢复了,此时需要终止线程甚至是终止虚拟机。这是一种不应该被我们应用层去捕获的异常。
  • catch OOM 的先决条件
    • 想通过 try-catch 避免 OOM,你需要两个先决条件:
      • 触发 OOM 的代码是开发者可控的。
      • 在 try 块中,申明对象并会申请了大段内存,导致触发 OOM。
    • 只有满足这两个条件,你才可以说,你对 OOM 有控制权,能够将其 catch 住。但是这通常不是合适的做法。
  • 是否建议catch住OOM
    • 不应该去主动 catch OOM。哪怕在此处catch住了,可App当前的状态也已经处于“濒危”状态。如果不采取措施,此时不崩,换一个地方也会崩。
  • 总结一下
    • OOM 能不能被 catch 住?在某些条件下可以。仅在我们可控的代码,并且在 try 块中存在申请大量内存的情况下,此时触发的 OOM,才是可以被 catch 住的。
    • 当我们 catch 住 OOM 的时候,我们应该主动释放一些我们可控的内存,做好内存管理,避免在后续的操作中,立即又会触发 OOM,导致崩溃。

其他介绍

01.关于博客汇总链接

02.关于我的博客

  • 我的个人站点:www.yczbj.org,www.ycbjie.cn
  • github:https://github.com/yangchong211
  • 知乎:https://www.zhihu.com/people/yang-chong-69-24/pins/posts
  • 简书:http://www.jianshu.com/u/b7b2c6ed9284
  • csdn:http://my.csdn.net/m0_37700275
  • 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
  • 开源中国:https://my.oschina.net/zbj1618/blog
  • 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
  • 邮箱:yangchong211@163.com
  • 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
  • segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
  • 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e

评论

留言