第1关:捕获异常
任务描述
本关任务:捕获程序的异常,输出异常处理的结果。
相关知识
为了完成本关任务,你需要掌握:1.如何捕获异常。
捕获异常
通过第一关我们知道,有一部分异常是需要程序员提前处理的,这种异常统一称为检测性异常,如果我们不处理,程序是不能编译通过的,在IDE中也会出现一条红线。
这个时候我们就必须处理这段可能出现异常的程序。
如何处理呢?
Java中提供了一个捕获异常的机制:try-catch
通过这两个单词的字面意思我们就能很好的理解了:try:尝试,catch:捕获;
尝试执行代码A和代码B如果这两段代码有一个出现了异常,就会执行catch中的语句,如果代码A、B都不存在异常就不会执行catch代码,最后继续执行代码C。
所以之前报错的代码我们这样写就没错啦:
在这里我们可以发现catch捕获的是FileNotFoundException,这是一个文件未找到异常,所以我们在捕获异常的时候最好要先明确异常的种类是什么。
好奇的同学可能会有疑惑,检测性异常可以用try-catch来处理,那运行时异常可不可以用try-catch来处理呢?
可不可以呢?自己验证一下吧!
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
编辑器中的代码运行时可能会有异常,请利用本关知识处理该异常。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
输入:
4
2
输出:
2
输入:
4
0
输出:
提示:捕获异常需要用特定的类,下表总结了常用的异常类:
非检测型异常:
异常 描述
ArithmeticException 当出现异常的运算条件时,抛出此异常。例如,一个整数”除以零”时,抛出此类的一个实例。
ArrayIndexOutOfBoundsException 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。
ClassCastException 当试图将对象强制转换为不是实例的子类时,抛出该异常。
IllegalArgumentException 抛出的异常表明向方法传递了一个不合法或不正确的参数。
IllegalMonitorStateException 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。
IllegalStateException 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。
IllegalThreadStateException 线程没有处于请求操作所要求的适当状态时抛出的异常。
IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
NegativeArraySizeException 如果应用程序试图创建大小为负的数组,则抛出该异常。
NullPointerException 当应用程序试图在需要对象的地方使用 null 时,抛出该异常
NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
StringIndexOutOfBoundsException 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。
… …
检测性异常:
异常 描述
ClassNotFoundException 应用程序试图加载类时,找不到相应的类,抛出该异常。
CloneNotSupportedException 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。
IllegalAccessException 拒绝访问一个类的时候,抛出该异常。
InstantiationException 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。
InterruptedException 一个线程被另一个线程中断,抛出该异常。
NoSuchFieldException 请求的变量不存在
NoSuchMethodException 请求的方法不存在
IOException及其子类 对文件或流的操作有误时,抛出异常
… …
代码实现
package step2;
import java.util.Scanner;
public class Task {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt();
int num2 = sc.nextInt();
/********* Begin *********/
try{
System.out.println(num1/num2);}
catch(ArithmeticException e){
System.out.print("除数不能为0");
}
/********* End *********/
}
}
第2关:抛出异常
任务描述
本关任务:抛出程序的异常。
相关知识
为了完成本关任务,你需要掌握:1. 如何使用throw和throws关键字。
throws 关键字
上一小节我们学习了如何处理捕获异常,但是我们有时候想偷个懒,不自己处理这些异常,可不可以呢?
答案是可以的!
我们可以将自己不想处理的异常交给别人来处理,怎么实现呢?
很简单我们只需要用throws关键字抛出该异常即可。
例如:
这个时候我们发现IDE报错了,提示我们这里有异常要处理,但是如果我们不想处理,就可以这样:
可以发现test方法内部没有报错了,但是调用test方法的地方报错了。是什么原因呢?
抛出异常,就像我们平常所说的“甩锅”,总有一个人要背锅,在Java中也一样异常最终总是要被处理或者被捕获的,所以我们如果在方法的括号后面抛出一个异常,那么该方法的调用者是必须要捕获这个异常或者将这个异常继续抛出的。
所以上面的错误就会有两种解决办法。
第一种:捕获异常:
第二种:把“锅”甩给Java虚拟机:
throw 关键字
throw关键字的作用是:主动抛出异常;
首先我们来看系统自动抛出异常:
public static void main(String[] args) {
int a = 10;
int b = 0;
System.out.println(a/b);
}
运行这段代码系统会自动抛出,java.lang.ArithmeticException异常。
这段程序使用throw关键字也可以实现:
public static void main(String[] args) {
int a = 10;
int b = 0;
if(b == 0){
throw new ArithmeticException("/ by zero");
}
System.out.println(a/b);
}
可以发现两段程序的运行结果都类似:
throw是语句抛出一个异常,一般是在代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常。
注意:使用throw关键字主动抛出检测性异常的时候,在方法名上必须使用throws表明调用这个方法可能存在要抛出的异常。
举个例子:
ArithmeticException属于运行时异常,是在运行时检测的,所以上述代码编译是能通过的,而FileNotFoundException是属于检测性异常,是在编译之前就需要处理的,所以第二段程序要加上throws才能通过编译。
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
异常的抛出和处理。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
预期输出:
该文件不存在。
代码实现
package step3;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Task {
public static void main(String[] args)throws FileNotFoundException{
test();
}
public static void test()throws FileNotFoundException{
File file = new File("abc");
if(!file.exists()){ //判断文件是否存在
//文件不存在,则 抛出 文件不存在异常
throw new FileNotFoundException("该文件不存在");
}else{
FileInputStream fs = new FileInputStream(file);
}
}
/********* End *********/
}
第3关:自定义异常
任务描述
本关任务:定义和使用自定义异常。
相关知识
为了完成本关任务,你需要掌握:
1.为什么要自定义异常;
2.怎么使用自定义异常。
自定义异常
前面谈到的都是系统自带的异常,但是如果我们是在开发一个复杂项目,就经常会遇到系统自带的异常不能满足我们的需求的情况,所以这个时候就需要我们自己来定义异常了。
使用自定义异常
我们一般使用继承Exception类的方式来自定义异常,那具体怎么进行呢?
很简单,我们只需要继承Exception,再将信息传递给父类就可以了:
class 自定义异常名 extends Exception{
//因为Exception已经实现了很多异常处理的方法了属性了,
//所以自定义异常只需要将信息传递给父类(使用super关键字)即可
}
一个简单的自定义异常:
输出:
我是自定义异常
这样就实现了一个自定义异常的定义和使用啦。
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
定义一个自定义异常,判断用户名是否小于三位,如果用户名小于三位,就抛出一个自定义异常。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
输入:
admin
输出:
用户名格式正确
输入:
ab
输出:
Exception in thread "main" step4.MyException: 用户名小于三位Exception at step4.Task.main(Task.java:13)
注意:因为抛出异常时会显示行号,请在13行抛出异常,否则评测可能不通过。
代码实现
package step4;
import java.util.Scanner;
public class Task {
/********* Begin *********/
public static void main(String[] args)throws MyException {
Scanner sc = new Scanner(System.in);
String username = sc.next();
//判断用户名
if(username.length()<3){
throw new MyException("用户名小于三位Exception");
}
else{
System.out.println("用户名格式正确");
}
}
}
class MyException extends Exception{
public MyException(){}
public MyException(String msg){
super(msg);
}
}
/********* End *********/