一、throw关键字用于抛出异常
1.1一个例子初步认识throw,请复制到编译器里感受一下
throw: 在Java中,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者
//实现一个获取数组中任意位置元素的方法
public static int getElement(int[]array,int index){
if (array==null){
throw new NullPointerException("传递的数组为null");//抛出空指针异常
}
if (index<0 || index>=array.length){
throw new ArrayIndexOutOfBoundsException("传递的数组下标越界");//抛出数组越界异常
}
return array[index];
}
测试该方法:
测试1:传入null指针
public static void main1(String[] args) {
int[] array1 = null;
getElement(array1,0);//测试NullPointerException
}
运行结果:
测试2:传越界下标
public static void main1(String[] args) {
int[] array2={1,2,3};
getElement(array2,-1);//测试ArrayIndexOutOfBoundsException
}
运行结果:
这两个测试可以看出throw都很好的完成任务了呢,让程序及时止损,及时停下来。
这里的两个异常都是在程序执行期间发生的,称为运行时异常。
运行时异常:RunTimeException以及其子类对应的异常。(比如上文的NullPointerException、ArrayIndexOutOfBoundsException都是其子类)
//注意:运行时异常指的是程序已经编译通过得到 class 文件了, 再由 JVM 执行过程中出现的错误,就是你点了运行的小三角形之后发生的事情哦~
1.2 throw注意点
注意点①:throw必须写在方法体内部
例子:尝试把throw语句写在类里,方法外。
class TestDemo1 {
throw new RuntimeException("测试throw语句是否能写在方法外 ");
}
由图可得:代码划红线,显然在方法外写throw语句会导致编译错误。所以不要把throw语句写在方法外。
这时候会有人问 :为什么throw必须写在方法体内部?
解释:当你在一个方法中使用throw语句时,你是在告诉编程语言:“嘿,我在这个方法中发现了一个问题,我不知道怎么处理,但我会把这个问题抛给调用我的那个人去处理。”这意味着异常是与该方法的执行环境紧密相关的。
如果你试图将throw语句放在方法外部,编程语言就会困惑:这个异常到底是从哪个方法抛出的呢?因为它不在任何方法的上下文中,所以编译器无法理解它应该被传递给谁来处理。
所以,将throw语句放在方法内部是必须的,因为这样可以清晰地表示异常是与该方法相关的。这也使得异常处理更加有序和可控。
【关于异常的小拓展】:受查异常和运行时异常
上面的代码划红线也是一种异常,称编译异常或受查异常(Checked Exception)
并且,注意代码划红线和代码变红的区别!
public static void main(String[] args) {
System.out.printn("注意看代码是字体变红,而不是下面划横线");
}
字体变红:语法错误或书写错误
在计算机编程中,语法错误或书写错误通常不被认为是受查异常。受查异常通常是在程序运行时可以预测和捕获的异常,例如试图访问不存在的文件或者网络连接失败。语法错误是在编译或解释阶段就发生的,通常指的是代码不符合语言的语法规则。与受查异常不同,语法错误无法通过异常处理机制捕获和处理,而是需要在代码编写阶段就修复。
注意点②:抛出的对象必须是Exception 或者 Exception 的子类对象
二、异常的处理方法1:throws声明异常
我们不能只抛出异常,而不解决异常,现在讲讲两种异常处理方法之一throws语句。
throws 用于异常声明。当方法中出现编译异常时,我就是不想改我的代码,就要对编译器声明异常,相当于对编译器说我就是要这样编,请让我运行吧。
编译器说:可以是可以,请你声明一下。
相当于给编译器签一份免责声明。报错之后,编译器就可以说,不关我的事。
2.1一个例子感受throws:
class Example {
// readFile()这个方法会抛出IOException异常
public void readFile() {
throw new java.io.IOException("File not found"); // 模拟抛出异常
}
这时编译器不认了哦,报红线,暗戳戳说:你这有异常我不给你运行。
这时候我们需要告诉编译器,我头铁,我就要!
class Example {
// 这个方法会抛出IOException异常,紧跟方法名添加throws java.io.IOException不报错了
public void readFile() throws java.io.IOException {
throw new java.io.IOException("File not found"); // 模拟抛出异常
}
注意点③:如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理 。
意思就是运行异常不用我们管!它都叫运行异常了,肯定能挺过编译的。JVM哥哥说剩下的它管。因此我们在编译阶段只需要处理受查异常!
解释:如果在代码中遇到 RuntimeException或其子类的异常,而没有进行显式的处理,那么异常会沿着调用栈向上传播,直到达到调用栈的顶部,也就是 JVM 的运行环境。在那里,异常会导致程序终止,并打印出异常的堆栈信息。这样做的好处在于,它提供了一种简单的方式来处理未预料到的异常情况,例如空指针异常、数组越界异常等,而不需要程序员在每个可能发生异常的地方都显式地处理它们,从而简化了代码的编写和维护。
注意点④:throws必须跟在方法的参数列表之后 且声明的异常必须是 Exception 或者 Exception 的子类 。这一点跟throw的是对应滴。
注意点⑤:方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开。如果抛出多个异常类型具有父子关系,直接声明父类即可。
注意点⑥. 调用声明抛出异常的方法时,调用者必须对该异常进行捕获,或者继续使用throws抛出。
class Example {
// 这个方法会抛出IOException异常
public void readFile() throws IOException {
throw new IOException("模拟抛出异常"); // 模拟抛出异常
}
public static void main(String[] args) throws IOException {
Example example = new Example();
example.readFile();
}
看到没,mian方法里也要声明 throws IOExeption,不然会报错哦。
编译器说:我可是很聪明的哦,这里也要签免责声明,别以为我不知道这里有问题。一生严谨的编译器(大家鼓掌)。
当然这里也可以不声明,但是要进行异常捕获(这里涉及到另一种异常处理方法try-catch,这一篇专注throw、throws,需要看try-catch的关注别的博客哦)。
以上就是关于throw和throws的全部内容。求三连!!会鼓励到我!!