Java异常

Java异常体系结构

Throwable

Error

Exception

运行时异常

编译时异常

受查异常和非受查异常

Java异常关键字

Java异常处理

自定义异常

Java异常常见面试题


Java异常是Java提供的一种识别及响应错误的一致性的机制。Java异常体制可以使程序中异常处理代码和正常业务代码分离,保证程序代码更加优雅,并能够提高程序的健壮性。

Java异常体系结构

Throwable

Throwable类是所有异常和错误的超类,两个直接子类为Error和Exception。

Throwable包含了其线程创建时线程执行堆栈的快照,它提供了printStackTrace()等接口用于获取堆栈跟踪数据等信息。

Error

Error类及其子类,程序中无法处理的错误,表示应用程序中出现了严重的错误。一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不总、方法调用栈溢出等。对于这类错误导致的应用程序中断,仅靠程序本身无法恢复和预防,遇到这样的错误,建议让程序终止。

它是由JVM产生和抛出的,通常有 Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。 比如 OutOfMemoryError:内存不足错误StackOverflowError:栈溢出错误。此类错误发生时,JVM 将终止线程。

Exception

Exception是程序本身可以处理的异常,这种异常分两大类:运行时异常和编译时异常。程序中应当尽可能去处理这些异常。

运行时异常

RuntimeException类及其子类属于运行时异常,表示在程序运行期间可能会出现的异常。

比如NullPointerException空指针异常、ArrayIndexOutBoundException数组 下标越界异常ClassCastException类型转换异常、ArithmeticExecption算术异常。

这些异常是不受查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

RuntimeException异常会由Java虚拟机自动抛出并自动捕获。

编译时异常

Exception中除了RuntimeException及其子类之外的异常。从程序语法角度讲是必须进行处理的异常。

Java编译器会检查它。如果程序中出现此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。

如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。

该异常我们必须手动在代码里添加捕获语句来处理该异常。

受查异常和非受查异常

Java中所有的异常可以分为受查异常和非受查异常。

受查异常:编译器要求必须处理的异常。RuntimeException 及其子类外,其他的 Exception 异常都属于受查异常

编译器会检查此类异常,也就是说当编译器检查到应用中的某处可能会此类异常时,将会提示你处理本异常要么使用trycatch捕获,要么使用方法签名中用 throws 关键字抛出,否则编译不通过。

非受查异常:编译器不hi进行检查并且不要求必须处理的异常,程序中出现此类异常,即使没有try-catch捕获,也没有使用throws抛出该异常,编译也会正常通过。

包含运行时异常(RuntimeException及其子类)和错误(Error)

Java异常关键字

  • try:用于监听。当try语句块内发生异常时,异常就被抛出。
  • catch:用来捕获异常。捕获try语句块中发生的异常。
  • finally:finally语句块总是会被执行。
  • throw:用于抛出异常
  • throws:用来声明该方法可能抛出的异常,用在方法签名上。

Java异常处理

throws直接抛出异常

通常,应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去。传递异常可以在方法签名处使用 throws 关键字声明可能会抛出的异常。

private static void readFile(String filePath) throws IOException {
    File file = new File(filePath);
    String result;
    BufferedReader reader = new BufferedReader(new FileReader(file));
    while((result = reader.readLine())!=null) {
        System.out.println(result);
    }
    reader.close();}

封装异常再抛出

有时我们会从 catch 中抛出一个异常,目的是为了改变异常的类型。多用于在多系统集成时,当某个子系统故障,异常类型可能有多种,可以用统一的异常类型向外暴露,不需暴露太多内部异常细节。

private static void readFile(String filePath) throws MyException {    
    try {
        // code
    } catch (IOException e) {
        MyException ex = new MyException("read file failed.");
        ex.initCause(e);
        throw ex;
    }
}

try-catch捕获异常

在一个 try-catch语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理。

private static void readFile(String filePath) {
    try {
       //可能会发生的异常
    } catch (FileNotFoundException e) {
        //针对FileNotFoundException异常进行处理
    } catch (IOException e){
       //针对IOException进行处理
    }
}

try-catch-finally

当方法中发生异常,异常处之后的代码不会再执行,如果之前获取了一些本地资源需要释放,则需要在方法正常结束时和 catch 语句中都调用释放本地资源的代码,显得代码比较繁琐,finally 语句可以解决这个问题。


public class ExceptionTest {
 
	public static void main(String[] args) {
		try {
			// 抛出(throw)异常
			System.out.println("执行try语句块,抛出异常");
			throw new Error();
		} catch (Exception e) {
			System.out.println("执行catch语句块,已捕捉到Exception异常");
			e.printStackTrace();
		} catch (Error e) {
			System.out.println("执行catch语句块,已捕捉到Error错误");
			e.printStackTrace();
		} finally {
			System.out.println("执行finally语句块");
		}
	}
}

注意:

  • catch不能独立于 try 存在。
  • catch里面不能没有内容
  • 在 try/catch 后面添加 finally 块并非强制性要求的。
  • try 代码后不能既没 catch 块也没 finally 块。
  • try里面越少越好。
  • try, catch, finally 块之间不能添加任何代码。
  • finally里面的代码最终一定会执行(除了JVM退出)
  • 如果程序可能存在多个异常,需要多个catch进行捕获。
  • 多个catch块时候,最多只会匹配其中一个异常类且只会执行该catch块代码,而不会再执行其它的catch块,且匹配catch语句的顺序为从上到下,也可能所有的catch都没执行。

finally的作用:

  • 无论try所指定的程序块中是否抛出异常,也无论catch语句的异常类型是否与所抛弃的异常的类型一致,finally中的代码一定会被执行到。
  • finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分之前,能够对程序的状态作统一的管理。
  • 通常在finally语句中可以进行资源的清除工作,如关闭打开文件、删除临时文件等。

finally注意事项

finally执行的实际是在方法返回之前(try或者catch中如果有return 会在这个return 之前执行finally)。

但是如果finally中也存在return语句,那么就会执行finally中的return,从而不会执行到try中原有的return。

一般不建议再finally中写return(会被编译器当作一个警告)

自定义异常

自定义异常通常会继承自Exception或者RuntimeException。继承及Exception的默认是受查异常,继承自RuntimeException的异常默认是非受查异常。

自定义异常应该总是包含如下的构造函数:

  • 一个无参的构造函数
  • 一个带有String参数的构造函数,并传递给父类的构造函数
  • 一个带有String参数和Throwable参数的构造函数,并都传给父类构造函数
  • 一个带有Throwable参数的构造函数,并传递给父类的构造函数
//自定义异常类OverdraftException
public class OverdraftException extends  Exception{
    private double deficit;

    public double getDeficit() {
        return deficit;
    }

    public OverdraftException() {
    }

    public OverdraftException(String message, double deficit) {
        super(message);
        this.deficit = deficit;
    }
}

Java异常常见面试题

error和Exception的区别?

  • Error类和Exception类的父类都是Throwable类。
  • Error 类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出等。对于这类 错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
  • Exception 类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复 运行,而不应该随意终止异常。
  • Exception 类又分为运行时异常(Runtime Exception)和受检查的异常(Checked Exception ),运行时异常;ArithmaticException,IllegalArgumentException,编译能通过,但是一运行就终止了,程序不会处理运行时异常,出现这类异常,程序会终止。而受检查的异常,要么用 try。。。catch 捕获,要么用 throws 字句声明抛出,交给它 的父类处理,否则编译不会通过。
 

throw和throws的区别?

throw:

  • throw语句用在方法体内,表示抛出异常,由方法体内的语句处理
  • throw是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行throw一定是抛出了某种异常。

throws

  • throws语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理
  • throws主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型
  • throws表示出现异常的以后在哪个可能性,并不一定会发生这种异常。

final、finally、finalize的区别?

  • final: 可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
  • finally: 一般作用在try-catch代码块中,在处理异常的时候,通常将一定要执行的代码放在finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
  • finalize: Object类的一个方法,在垃圾回收器执行的时候会调用被回收对象的该方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。该方法更像是一个对象声明周期的临终方法,当该方法被系统调用则代表该对象即将“死亡”。我们主动行为上调用该方法并不会导致该对象“死亡”,这是一个被动的方法(其实就是回调方法),不需要我们调用。

常见的RuntimeException有哪些?

  • java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
  • java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序 试图通过字符串来加载某个类时可能引发异常。
  • java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
  • java.lang.IndexOutOfBoundsException 数组下标越界异常,常见于操作数组对象时发生。
  • java.lang.IllegalArgumentException 方法传递参数错误。
  • java.lang.ClassCastException 数据类型转换异常
  • java.lang.NoClassDefFoundException 未找到类定义错误
  • SQLException SQL 异常,常见于操作数据库时的 SQL 语句错误
  • java.lang.InstantiationException 实例化异常
  • java.lang.NoSuchMethodException 方法不存在异常
     

 

 

 

 

 

  • 10
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值