
Educoder/头歌JAVA——JAVA面向对象:JAVA中的异常
相信大家在学习 Java 的过程中或多或少都遇到了很多错误,这些错误一般都是以Exception结尾的,这些都是 Java 异常类的衍生类,我们会好奇 Java 中的异常到底是怎么工作的,又是如何起作用的,如何在我们程序出错的时候提醒我们的?其中的原理又是什么呢?本次实训我们就来系统的学习 Java 中非常重要的模块 ——Java 异常。
第1关:Java 中的异常处理机制
相关要求
什么是异常
异常:程序在运行过程中产生的不正常情况。
程序在运行的时候,发生了一些不被预期的事件,从而没有按照我们编写的代码执行,这就是异常。异常是Java中的错误,但是并不是所有的错误都是异常,比如说,你在定义变量名的时候没有依照Java的规则,在语句的结尾少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;
不过如果你用System.out.println(5/0),那这个时候你的程序是可以正常编译的,但是在运行的时候,因为你用0做了除数,会抛出 java.lang.ArithmeticException 的异常。
异常的原因有很多种,比如:
-
输入了错误的数据,比如:程序需要的是
int类型数据,而用户输入了一串字符串; -
对象没有初始化就调用:下面这段代码就会提示空指针异常;
String str = null;int length = str.length();
-
要打开的文件不存在;
-
网络通信时连接中断,或者JVM内存溢出。
要理解Java中的异常是如何工作的,你需要掌握以下三种类型的异常:
-
检查性异常;
-
运行时异常;
-
错误。
检查性异常
例如我们要打开一个文件时,这段代码就可能存在异常,因为这个文件很有可能并不存在。
File f = new File("G://test.java");FileInputStream fs = new FileInputStream(f);
这里G盘下的test.java文件就可能不存在,这个时候运行这段代码就可能会出异常,所以在我们编写代码的时候IDE会提示我们要处理这段代码可能出现的异常。
如果我们不处理的话,程序是不能被编译的。
运行时异常
运行时异常程序员可以不去处理,当异常出现时,虚拟机会处理。常见的运行时异常有空指针异常。
常见的运行时异常:
ClassCastException(类转换异常)IndexOutOfBoundsException(数组越界)NullPointerException(空指针)ArrayStoreException(数据存储异常,操作数组时类型不一致)
错误
错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
Exception 类
所有的异常类都是从 java.lang.Exception 类继承的子类。
Exception 类是 Throwable 类的子类。除了Exception类之外,Throwable还有一个子类Error 。
Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
Error 用来指示运行时环境发生的错误。
例如,JVM内存溢出。一般地,程序不会从错误中恢复。
异常类有两个主要的子类:IOException 类和 RuntimeException 类。



第2关:捕获异常
相关知识
捕获异常
通过第一关我们知道,有一部分异常是需要程序员提前处理的,这种异常统一称为检测性异常,如果我们不处理,程序是不能编译通过的,在IDE中也会出现一条红线。

这个时候我们就必须处理这段可能出现异常的程序。
如何处理呢?
Java中提供了一个捕获异常的机制:try-catch

通过这两个单词的字面意思我们就能很好的理解了:try:尝试,catch:捕获; 尝试执行代码A和代码B如果这两段代码有一个出现了异常,就会执行catch中的语句,如果代码A、B都不存在异常就不会执行catch代码,最后继续执行代码C。
所以之前报错的代码我们这样写就没错啦:

在这里我们可以发现catch捕获的是FileNotFoundException,这是一个文件未找到异常,所以我们在捕获异常的时候最好要先明确异常的种类是什么。
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
- 编辑器中的代码运行时可能会有异常,请利用本关知识处理该异常。
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{
int ans =num1/num2;
}catch(ArithmeticException a){
System.out.println("除数不能为0");
}
System.out.println(num1/num2);
/********* End *********/
}
}
第3关:抛出异常
相关知识
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 {
/********* Begin *********/
//请在合适的部位添加代码
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 *********/
}
第4关:自定义异常
相关知识
自定义异常
前面谈到的都是系统自带的异常,但是如果我们是在开发一个复杂项目,就经常会遇到系统自带的异常不能满足我们的需求的情况,所以这个时候就需要我们自己来定义异常了。
使用自定义异常
我们一般使用继承Exception类的方式来自定义异常,那具体怎么进行呢?
很简单,我们只需要继承Exception,再将信息传递给父类就可以了:
class 自定义异常名 extends Exception{//因为Exception已经实现了很多异常处理的方法了属性了,//所以自定义异常只需要将信息传递给父类(使用super关键字)即可}
一个简单的自定义异常:

输出:我是自定义异常
这样就实现了一个自定义异常的定义和使用啦。
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
- 定义一个自定义异常,判断用户名是否小于三位,如果用户名小于三位,就抛出一个自定义异常。
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");
}
if(username.length()>=3){
System.out.println("用户名格式正确");
}
}
}
class MyException extends Exception{
public MyException(){
}
public MyException(String err){
super(err);
}
}
/********* End *********/
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐


所有评论(0)