异常:Exception
1、分类:
1、编译期异常:checkedException。
在代码中存在该异常,是不能编译通过的,即不能生成.class文件,必须处理完所有的编译期异常才能运行代码。
2、运行期异常:RuntimeException
运行过程中抛出的错误。
2、JDK常见异常:
1、运行期异常:
NUllPointerWxception 空指针异常,使用了没有实例化的对象引用。
ArithmeticException 算数异常,被0除了
InputMissmatchException 输入类型不匹配异常,输入了非法字符
ArrayIdexOutOfBoundsException 数组下标越界异常,访问了不存在的数组的下标。
2、编译期异常:
IOException 输入输出异常,属于编译期异常,访问了一个不存在的文件或者目录。
3、JDK常见异常的继承关系
基本上就是checkedException→Exception→Throwable→Object
或者RuntimeException→Exception→Throwable→Object
下面我会通过一个例子来看SUN公司如何定义异常来理解异常之间的继承关系。
4、那么我们遇到异常该怎么办呢?
思路有2:
1、自己能解决就解决。专业术语叫try-catch-finally
2、不能解决的话,谁用的话让谁去解决。即抛出异常让调用者去解决。那么所有的调用者都不解决的话,最终会交给JVM来解决,JVM会抛出简单异常信息。专业术语叫throws
我们首先来讲try-catch-finally
语法:
try{
//try代码块写圈住可能会出现异常的代码
}catch(catch参数 形参){//catch参数:写可能会出现异常的对象类型
//catch代码块,当异常产生的时候会执行
}
使用try-catch的程序执行的流程:
一、没有异常的情况:
1、执行try代码块中的所有的代码
2、跳过catch代码块中的所有代码
3、执行catch代码块后边的代码
二、try代码块中出现异常
1、try代码块中出现异常(产生了一个异常对象),try块中后续代码会被跳过。
2、如果产生的异常对象是catch参数中的异常类型的实例,那么该异常对象会被捕获。catch形参变量(通常是e)指向被捕获的对象。通过变量e就可以操作被捕获的异常对象。执行catch代码块中的代码。
3、如果产生的异常对象不是catch参数中的一场类型的实例,程序崩溃。
4、如果捕获了产生的异常对象,执行完catch代码块后,执行catch后的内容。程序正常结束。
下面通过一个计算器例子来理解其用法
public class TestException {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入除数:");
int num0 = scanner.nextInt();
System.out.println("请输入被除数:");
int num1 = scanner.nextInt();
int result = 0;
try {
result = num0 / num1;
System.out.println("计算结果为:" + num0 + "/" + num1 + "=" + result);
//上面的代码一旦产生了异常,那么会跳过try代码块中后续的代码,执行catch 中的代码
} catch (ArithmeticException e) {
//打印
e.printStackTrace();
System.out.println("您输入了非法的除数,不能为0,请您下次注意,不是我们的责任哦!");
}
}
}
5、那么有多个代码块可能出现异常呢?
此时我们需要多重try-catch
public class TestException {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入除数:");
int num0 = scanner.nextInt();
System.out.println("请输入被除数:");
int num1 = scanner.nextInt();
int result = 0;
result = num0 / num1;
System.out.println("计算结果为:" + num0 + "/" + num1 + "=" + result);
} catch (ArithmeticException e) {
//打印
e.printStackTrace();
System.out.println("您输入了非法的除数,不能为0,请您下次注意,不是我们的责任哦!");
}
catch (InputMismatchException e){
e.printStackTrace();
System.out.println("您输入了非数值型的数据,不能进行除法运算!请重新输入!");
} catch (Exception e){
e.printStackTrace();
System.out.println("非法的操作!");
}
}
}
这时我们需要注意的是
catch (Exception e){
e.printStackTrace();
System.out.println("非法的操作!");
}
只能放到最后,因为他的异常类型范围是最大的。如果放在其他异常类型前边,会报如下错误:其他类型异常已经捕获。它可以捕获所有的异常对象。Exception 是所有的异常类型的父类。
6、finally的使用
finally代码块中放在catch的后面,一般是存放不论何种情况一定都要执行的代码。如果某些代码是必须要被执行的,放到其中。
其中:用到了异常对象常用的两个方法:
System.exit(0):结束虚拟机
e.printStackTrace:打印被捕获异常对象的堆栈信息,通过该信息可以定位异常位置。
public class TestException {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入除数:");
int num0 = scanner.nextInt();
System.out.println("请输入被除数:");
int num1 = scanner.nextInt();
//可能产生异常的代码
int result = 0;
result = num0 / num1;
System.out.println("计算结果为:" + num0 + "/" + num1 + "=" + result);
//上面的代码一旦产生了异常,那么会跳过try代码块中后续的代码,执行catch 中的代码
//结束虚拟机。不会执行finally 中的代码。
System.exit(0);
//即使代码中存在return 语句,都会执行 finally代码块
return;
} catch (ArithmeticException e) {
//打印
e.printStackTrace();
System.out.println("您输入了非法的除数,不能为0,请您下次注意,不是我们的责任哦!");
}
catch (InputMismatchException e){
e.printStackTrace();
System.out.println("您输入了非数值型的数据,不能进行除法运算!请重新输入!");
} catch (Exception e){
e.printStackTrace();
System.out.println("非法的操作!");
}
}
}
7、我们来看看SUN公司是如何定义的异常类。
以File类中createNewFile()方法为例
public class IoException {
public static void main(String[] args) throws IOException {
test();
//第一种方式
File file=new File("x:/1.txt");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
//抛给调用者来处理异常
//第二种方式
static void test() throws IOException {
File file=new File("c:/1.txt");
file.createNewFile();
}
}
报错信息如下:
那么报错信息为什么是全包名:具体信息呢?
下面我们看SUN公司源码分析:
该方法定义的异常方法如下:
抛出的异常对象需要重写toString方法,当打印对象的时候会显示报错信息。
该方法的toString写在父类中继承关系如下:
IOException>Exception>Throwable
既然我们已经搞懂SUN公司是如何定义异常的,那我们能不能自己写一个异常类呢?
答案是当然可以。
我们先补充下知识点:
throw:是java 的关键字,在方法体中使用,后面跟的是异常对象,只能跟一个异常对象。用于在方法体中抛出一个异常对象。
throws:是 java 的关键字,在方法的参数列表后使用,后面跟的是异常的类型。可以跟多个异常类型,使用逗号分隔。用于声明方法使用的时候可能会抛出的异常对象的类型。
现在开始回答文章题目:我们为什么要抛出去一个对象?
因为对象重写toString方法后,会携带具体的报错信息。
好了,我们现在开始写自定义异常类:
定义:一个学生类具有性别属性,当设置性别的时候,如果传入的 不是 【男、女】那么抛出一个自定义性别异常:GenderException。
*创建一个学生类:
我们在设置性别的时候做了如代码中的处理
public class Student {
private String name;
private String gender;
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) throws Exception{
if(!(gender.equals("男")||gender.equals("女"))){
throw new GenderException(gender);
}
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
public class DefinedStudentException {
public static void main(String[] args) {
Student s = new Student();
s.setName("小红");
try {
s.setGender("男o");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(s);
}
}