Java throws和throw:声明和抛出异常
如果觉得写的还可以,点个赞支持一下笔者呗!你的点赞和关注会让我更快更新哦。笔者会持续更新关于Java和大数据有关的文章。目前集中精力在更新java框架的内容。
Java 中的异常处理除了捕获异常和处理异常之外,还包括声明异常和拋出异常。实现声明和抛出异常的关键字非常相似,它们是 throws 和 throw。可以通过 throws 关键字在方法上声明该方法要拋出的异常,然后在方法内部通过 throw 拋出异常对象。本节详细介绍在 Java 中如何声明异常和拋出异常。
throws 声明异常
当一个方法产生一个它不处理的异常时,那么就需要在该方法的头部声明这个异常,以便将该异常传递到方法的外部进行处理。使用 throws 声明的方法表示此方法不处理异常。throws 具体格式如下:
returnType method_name(paramList) throws Exception 1,Exception2,…{…}
其中,returnType 表示返回值类型;method_name 表示方法名;paramList 表示参数列表;Exception 1,Exception2,… 表示异常类。
如果有多个异常类,它们之间用逗号分隔。这些异常类可以是方法中调用了可能拋出异常的方法而产生的异常,也可以是方法体中生成并拋出的异常。
使用 throws 声明抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由向上一级的调用者处理;如果 main 方法也不知道如何处理这种类型的异常,也可以使用 throws 声明抛出异常,该异常将交给 JVM 处理。JVM 对异常的处理方法是,打印异常的跟踪栈信息,并中止程序运行,这就是前面程序在遇到异常后自动结束的原因。
例 1
创建一个 readFile() 方法,该方法用于读取文件内容,在读取的过程中可能会产生 IOException 异常,但是在该方法中不做任何的处理,而将可能发生的异常交给调用者处理。在 main() 方法中使用 try catch 捕获异常,并输出异常信息。代码如下:
importjava.io.FileInputStream; importjava.io.IOException; publicclassTest04 { publicvoidreadFile() throwsIOException { // 定义方法时声明异常FileInputStreamfile=newFileInputStream("read.txt"); // 创建 FileInputStream 实例对象intf; while ((f=file.read()) !=-1) { System.out.println((char) f); f=file.read(); } file.close(); } publicstaticvoidmain(String[] args) { Throwst=newTest04(); try { t.readFile(); // 调用 readFHe()方法 } catch (IOExceptione) { // 捕获异常System.out.println(e); } } }
以上代码,首先在定义 readFile() 方法时用 throws 关键字声明在该方法中可能产生的异常,然后在 main() 方法中调用 readFile() 方法,并使用 catch 语句捕获产生的异常。
注意;主方法中即使只有一个int result=test();也能执行,只是不能显示”除数不允许为零“,但是如果换成Exception,则不能运行。
接受多异常
但是如果抛出Exception异常(父类)
那么在多catch之中必须要包含Exception捕捉,不然就会报错。
注意到第30行的代码没有用try,即使test()已经声明可能会有异常,在编译并不会报错,也可以运行(但是对用户已经没有提示意义了)。但是如果throws后面接Exception时,就会报错,原因是下图throws的异常是 非检查异常,在编译的时候并不会报错,而Exception包括非检查异常和检查异常,所以会报错。
那么如果在写代码时,编译器不会提示你test()可能包含的异常的时候,我们需要写注释文档,如下图所示:
仔细观察,这个虽然没处理而且是Exception但也没有报错的原因是因为主方法也抛出了这个异常交给系统处理。
方法重写时声明抛出异常的限制
使用 throws 声明抛出异常时有一个限制,是方法重写中的一条规则:子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型的子类或相同,子类方法声明抛出的异常不允许比父类方法声明抛出的异常多。看如下程序。
publicclassOverrideThrows { publicvoidtest() throwsIOException { FileInputStreamfis=newFileInputStream("a.txt"); } } classSubextendsOverrideThrows { // 子类方法声明抛出了比父类方法更大的异常// 所以下面方法出错publicvoidtest() throwsException { } }
上面程序中 Sub 子类中的 test() 方法声明抛出 Exception,该 Exception 是其父类声明抛出异常 IOException 类的父类,这将导致程序无法通过编译。
所以在编写类继承代码时要注意,子类在重写父类带 throws 子句的方法时,子类方法声明中的 throws 子句不能出现父类对应方法的 throws 子句中没有的异常类型,因此 throws 子句可以限制子类的行为。也就是说,子类方法拋出的异常不能超过父类定义的范围。
throw 拋出异常(主动抛出异常)
注意:throw引号里面的内容必须要配合 e.printStackTrace();使用。
throw抛出异常对象的处理方案:
1.通过try catch包含throw语句--自己抛自己处理
2.通过throws在方法声明处抛出异常类型--谁调用谁处理
注意:第八行的throw的必须是13行throw的父类或者同级,比如第八行是throw throwable也是可以的,同时也要存在有至少一个catch语句的范围不能小于抛出来的异常对象。
- 并且13行的如果是Exception,那么一定要加上throws Exception.
- 如果是不检查异常,那么throws 可以加也可以不加。
如果没有catch处理异常,则由系统进行异常处理。
与 throws 不同的是,throw 语句用来直接拋出一个异常,后接一个可拋出的异常类对象,其语法格式如下:
throw ExceptionObject;
其中,ExceptionObject 必须是 Throwable 类或其子类的对象。如果是自定义异常类,也必须是 Throwable 的直接或间接子类。例如,以下语句在编译时将会产生语法错误:
throw new String("拋出异常"); // String类不是Throwable类的子类
当 throw 语句执行时,它后面的语句将不执行,此时程序转向调用者程序,寻找与之相匹配的 catch 语句,执行相应的异常处理程序。如果没有找到相匹配的 catch 语句,则再转向上一层的调用程序。这样逐层向上,直到最外层的异常处理程序终止程序并打印出调用栈情况。
throw 关键字不会单独使用,它的使用完全符合异常的处理机制,但是,一般来讲用户都在避免异常的产生,所以不会手工抛出一个新的异常类的实例,而往往会抛出程序中已经产生的异常类的实例。
区别
throws 关键字和 throw 关键字在使用上的几点区别如下:
- throws 用来声明一个方法可能抛出的所有异常信息,表示出现异常的一种可能性,但并不一定会发生这些异常;throw 则是指拋出的一个具体的异常类型,执行 throw 则一定抛出了某种异常对象。
- 通常在一个方法(类)的声明处通过 throws 声明方法(类)可能拋出的异常信息,而在方法(类)内部通过 throw 声明一个具体的异常信息。
- throws 通常不用显示地捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法; throw 则需要用户自己捕获相关的异常,而后再对其进行相关包装,最后将包装后的异常信息抛出。