关于java异常整理

java中异常有哪些,怎么使用?
我想着也是大家面试中常见的一个问题,那么这里就写写对于这个点的一些整理

什么是异常(从源码剖析)

先看下百度百科是怎么说的

异常:程序在运行过程中发生由于外部问题(如硬件错误、输入错误)等导致的程序异常事件。
(在Java等面向对象的编程语言中)异常本身是一个对象,产生异常就是产生了一个异常对象

异常跟错误的区别

异常都是运行时的。编译时产生的不是异常,而是错误(Error)。
需要注意的是,程序设计导致的错误(Error)不属于异常(Exception)。

异常处理体系

Throwable:是所有Errors和Exceptions的superclass
  |- Error:系统内部错误,这类错误由系统进行处理,程序本身无需获取处理
  |- Exception:可处理的异常
      |- 非运行时异常
          |- IOException
              |- EOFException
              |- FileNotFoundException
              |- MalformedURLException
              |- UnknownHostException
          |- ClassNotFoundException
          |- CloneNotSupported
      |- RuntimeException:可以捕获的异常,也可以不捕获的异常;是those异常的超类
          |- ArithmeticException
          |- ClassCastException
          |- IllegalArgumentException
          |- IllegalStateException
          |- IndexOutOfBoundsException
          |- NoSuchElementException
          |- NullPointerException

异常产生的时间和执行顺序

  • 程序编译期间,由编译器对代码进行编译,遇到错误会给出提示
  • 程序运行期间,运行时出现了不可预料的错误,抛出异常

执行顺序:

  • new一个异常对象
  • 终止当前的执行程序
  • 弹出异常对象的引用
  • 异常处理机制接管被终止的执行程序
  • 寻找一个恰当的地点继续执行程序

自定义异常

  • 两个构造器,一个是默认构造器,一个是接受字符串作为参数
  • 使用throw抛出异常,可以把异常处理看成一种不同的返回机制

源码分析

Throwable:Throwable是整个异常的超类

public Throwable() {
    fillInStackTrace();
}
public Throwable(String message) {
    fillInStackTrace();
    detailMessage = message;
}
public Throwable(String message, Throwable cause) {
    fillInStackTrace();
    detailMessage = message;
    this.cause = cause;
}
public Throwable(Throwable cause) {
    fillInStackTrace();
    detailMessage = (cause==null ? null : cause.toString());
    this.cause = cause;
}

在Throwable的构造方法中,我们可以看到的两个参数是message和cause,这两个就是异常的信息和产生异常的原因;
我们还看到fillInStackTrace这个方法: 这个方法就是在Throwable对象中填充执行堆栈信息,然后记录在当前线程的栈帧状态

private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0];
private StackTraceElement[] stackTrace = UNASSIGNED_STACK;

public synchronized Throwable fillInStackTrace() {
   if (stackTrace != null ||
            backtrace != null /* Out of protocol state */ ) {
            fillInStackTrace(0);
            stackTrace = UNASSIGNED_STACK;
   }
   return this;
}
private native Throwable fillInStackTrace(int dummy);

上面这个方法定义了一个数组,数组的类型是StackTraceElement。而且采用了final类型的数组,证明其不可在引用其他类型

那么ELement包含的内容就是各种信息了

public final class StackTraceElement implements java.io.Serializable {
//可以看出这是一个final class,说明他是一个基础类不许被继承。
    private String declaringClass;
    // 方法的类名
    private String methodName;
    //方法名
    private String fileName;
    //文件名
    private int    lineNumber;
    // 调用的行数
// =========构造器======
public StackTraceElement(String declaringClass, String methodName,
                         String fileName, int lineNumber) {
    this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null");
    this.methodName     = Objects.requireNonNull(methodName, "Method name is null");
    this.fileName       = fileName;
    this.lineNumber     = lineNumber;
}

回到fillInStackTrace方法,它还调用了fillInStackTrace(0) ,是由下面这个方法实现的

private native Throwable fillInStackTrace(int dummy);

**这是一个native方法,就是去底层本地方法来获取当前线程的堆栈信息。据悉这是一个非常耗时的方法。**如果我们仅仅需要用到异常的传播性质,而不关心异常的堆栈信息,那么完全可以在自定义异常类的时候重写fillInStackTrace()方法。

后续的printStackTrace就是在栈帧中输出对应的信息。

Error与Exception的区别

Error

程序在运行期间出现了十分严重,不可恢复的错误

======Error======
public class Error extends Throwable {
 static final long serialVersionUID = 4980196508277280342L;
 public Error() {
     super();
 }
 public Error(String message) {
     super(message);
 }
 public Error(String message, Throwable cause) {
     super(message, cause);
 }
 public Error(Throwable cause) {
     super(cause);
 }
 protected Error(String message, Throwable cause, boolean enableSuppression,
                 boolean writableStackTrace) {
     super(message, cause, enableSuppression, writableStackTrace);
 }
}

Exception

Exception是应用层面上最顶层的异常类

======Exception======
public class Exception extends Throwable {
 static final long serialVersionUID = -3387516993124229948L;
 public Exception() {
     super();
 }
 public Exception(String message) {
     super(message);
 }
 public Exception(String message, Throwable cause) {
     super(message, cause);
 }
 public Exception(Throwable cause) {
     super(cause);
 }
 protected Exception(String message, Throwable cause, boolean enableSuppression,
                     boolean writableStackTrace) {
     super(message, cause, enableSuppression, writableStackTrace);
 }
}

  • Exception和Error继承Throwable类,在java中只有Throwable类型的实例才能被抛出(throw)或者捕获(catch),它是异常处理机制的基本类型。
  • Exception和Error体现了java平台针对不同异常情况的分类。Exception是程序正常运行过程中,可以预料的意外情况,可能并且应该被捕获,并进行处理。Error正常情况下不大可能出现的情况,绝大部分的Error都会导致程序状态不正常,不可恢复,既然是非正常情况,所以不便也不需要处理,例如OutOfMemoryError之类都是Error的子类
  • Exception分为检查型异常和非检查型异常。检查型异常必须在源码中进行捕获处理,这是编译检查的一部分。除了RuntimeExceion及其子类之外的异常都是检查型异常。非检查型异常就是所谓的RuntimeExceion,类似NullPointerException,ArrayIndexOfBoundException就是非检查型异常,通常是可以通过编码避免的逻辑错误,具体根据需要判断是否需要捕获,编译期不检查,如果抛出了非检查型异常,那就是编码逻辑有问题,要解决。

异常使用

try{}catch(Exception e){}finally{}和throws两种办法。try{}catch(Exception e){}finally{}是在方法中对异常进行捕获,catch可以写多个,Java运行时系统从上到下分别对每个catch语句处理的例外类型进行检测,直到找到类型相匹配的catch语句为止。(具体的就不过多赘述)throws是出现在方法头部,个人理解算是在最外层抛出异常。

注意点:

  • 尽量不要捕获类似Exception这样的通用异常,二十应该捕获特定异常
  • 不要生吞(swallow)异常!
    • 生吞异常,往往是基于这段代码可能不会发生,或者感觉忽略异常是无所谓的,但是千万不要在产品代码中做这种设定
  • try-catch代码段会产生额外的性能开销,他往往会影响jvm对代码进行优化,所以建议仅捕获有必要的代码段,而不是一个大的try包住整段代码。
  • java没实例化一个Exception都会对当前的栈进行快照,这是一个相对比较重的操作,如果发生频繁,产生大量内存。

你可能感兴趣的:(面试题)