一、throw 和 throws 的用法
1、throw:异常的抛出
- 定义 : 一个方法不处理这个异常,而是调用层次向上传递,谁调用这个方法,这个异常就由谁来处理。
- 位置:在方法体内使用throw,进行异常抛出
- 语法:将产生的异常抛出(强调的是动作),抛出的既可以是异常的引用,也可以是异常对象。
public void todo() throws Exception {
throw new Exception("除数不能为0");
}
注意 : 调用可能会抛出异常的方法,必须添加 try-catch 代码块尝试去捕获异常 ,或者 添加throws 声明 来将异常 抛出给更上一层的调用者进行处理。这里需要注意一个细节:新的异常包含原始异常的所有信息,根据这个我们可以去追溯最初异常发生的位置,
public class TestException { /** * 通过throw抛出异常: throw new Exception("除数不能为0") * 由于抛出的是Exception对象(包含受检异常和非受检异常),所以需要在方法声明时指定throws */ public static void devide(int numOne ,int numTwo) throws Exception{ if(numTwo == 0) { throw new Exception("除数不能为0"); } System.out.println("-----1111111--------"); System.out.println("计算结果:"+(numOne / numTwo)); System.out.println("-----2222222--------"); } /** * 调用异常方法时,需要通过try/catch,进行异常处理 * 如果不处理,可将异常通过throws继续向上抛出 */ public static void todo(int numOne,int numTwo){ try { devide(numOne,numTwo); } catch (Exception e) { e.printStackTrace(); } System.out.println("-----3333333--------"); } /** * 不处理异常,将异常通过throws继续向上抛出 */ public static void notHandel(int numOne,int numTwo) throws Exception { devide(numOne,numTwo); } /** * 主方法*/ public static void main(String[] args) { todo(28,7); } }
//程序执行结果: -----1111111-------- 计算结果:4 -----2222222-------- -----3333333--------
2、throw 和 throws 的区别
throw | throws | |
意义 | 强调动作,指方法主动抛出异常 | 表示一种倾向、可能会抛出异常,但不一定实际发生 |
使用位置 | 在方法体内使用 | 在方法名或参数列表后、方法体前使用 |
语法定义 | 后跟的是异常对象,或者异常对象的引用 | 后跟的是异常类,可以一个,可以多个,多个用逗号隔开 |
对方法的影响 | throw用户抛出异常,当在当前方法中抛出异常后,当前方法执行结束(throw 后,如果有finally语句的话,会执行到finally语句后再结束。)。可以理解成return一样。 | throws : 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。用它修饰的方法向调用者表明该方法可能会抛出异常 |
二、RuntimeException运行时异常
1、运行时异常定义
程序在运行过程中出现的异常,称为运行时异常,RumtimeException 是 Exception 的一个子类 。
public class RuntimeException extends Exception { ……. }
2、运行时异常的使用
自定义异常时,如果该异常的发生,无法继续进行后续的运行,就让自定义异常类继承运行时异常RuntimeException。
/** * 自定义异常 */ class MyException extends RuntimeException{ public MyException() { } public MyException(String message) { super(message); } public MyException(String message, Throwable cause) { super(message, cause); } public MyException(Throwable cause) { super(cause); } public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }
3、运行时异常的特点
一般来说,我们在方法体内出现异常,我们用throw 关键字 将 异常对象或 异常对象的引用抛出,如果当前方法无法处理异常,那么必须在方法的参数列表后方法体前 必须 用 throws 声明异常所属类,交给调用者去处理。
但是RuntimeException是非常特殊的子类,你可以不用throw和throws,哪怕你throw了,也没必要thtows,即使你throws了,调用者也没必要try-catch
- 如果在函数内容中抛出该类异常或其子类异常,函数上可以不用声明,编译一样通过
- 如果在函数上声明该异常,调用者可以不同处理(try-catch),编译一样通过
为什么不用声明 ?
之所以不用在函数上声明,是因为不需要让调用者处理,当该异常发生,希望程序停止,因为在运行时,出现了无法继续运算的情况,希望程序停止后由程序员对代码进行修正。
public class TestException { /** * throw抛出的是运行时异常,所以不需要调用者去处理(因此不需要加throws) */ public static void devide(int numOne ,int numTwo) { if(numTwo == 0) { throw new RuntimeException("除数不能为0"); } System.out.println("-----1111111--------"); System.out.println("计算结果:"+(numOne / numTwo)); System.out.println("-----2222222--------"); } /** * 调用者不需要处理运行时异常 */ public static void todo(int numOne,int numTwo){ devide(numOne,numTwo); } /** * 主方法 */ public static void main(String[] args) { todo(28,7); } }
//程序执行结果: -----1111111-------- 计算结果:4 -----2222222--------
三、ckecked异常(受检异常) 和 运行时异常 :二者的区别
异常分两种:检查异常和非检查异常(运行时异常)
- 检查异常 : 编译时能够被检测的异常 (throw后,方法有能力处理就try-catch处理,没能力处理就必须throws)。编译不通过,检查语法(其实就是throw和throws的配套使用)。
- 运行时异常 : 编译时不被检查的异常(运行时异常。RuntimeException及其子类)。编译通过。
1、机制上的区别
主要表现在以下两个方面 :
- (1)如何定义方法
- (2)如何处理抛出的异常
运行时异常,不需要用throws 声明抛出 异常对象所属类,也可以不用throw 抛出异常对象或异常引用。对于调用该方法,也不需要放于 try-catch 代码块中。(为什么 ? 如果你捕获它,就会冒这么一个风险:程序代码错误被掩盖在运行中无法察觉)
而检查异常 : 一旦 用throw 抛出异常,必须被处理。如果当前方法可处理异常,那么直接在该方法内用try-catch 去处理。如果当前方法不具备处理该异常的能力,那么就必须在参数列表后方法体前用 throws 声明异常所属的类,交给调用者(方法) 去处理 。
2、逻辑上的区别
从逻辑的角度来看, checked 异常 和 RuntimeException 有着不同的使用目的,检查性异常用来指示一种调用方能够直接处理的异常情况(例如: 用户输入错误,程序可以直接捕获并处理,提示用户输入错误), 而RuntimeException是用来指调用方本身无法处理或回复的程序错误(例如,你封装个类库给别人用,当别人调用你库中某个方法是,需要传入某些参数,如果用户传入的参数不合法,你自己没办法处理,那么此刻你抛出的就应该是运行时异常)。
被博客部分内容转载自CSDN: 原作者:YFL_iOS 原文地址:https://blog.csdn.net/qq_18505715/article/details/76696439