目录
throws异常处理
基本介绍
throws异常处理注意事项和使用细节
自定义异常
基本概念
自定义异常的步骤
throw 和throws的区别
本章作业
第一题
第二题
第三题
第四题
1)如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
代码演示:
小细节:可以直接使用快捷键alt+Enter
package idea.chapter12.throws_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Throws01 {
public static void main(String[] args) {
}
public void f2() throws FileNotFoundException, NullPointerException, ArithmeticException {
//这里我们创建了一个文件流对象
//1. 这里的异常是一个FileNotFoundException 编译异常
//2. 使用前面讲过的 try-catch-finally
//3. 使用throws ,抛出异常, 让调用f2方法的调用者(方法)处理
//4. throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类 也可以写Exception因为Exception是FileNotFoundException的父类
//5. throws 关键字后也可以是 异常列表, 即可以抛出多个异常
FileInputStream fis = new FileInputStream("d://aa.txt");
}
}
1)对于编译异常,程序中必须处理,比如 try-catch或者throws
2)对于运行时异常,程序中如果没有处理,默认就是throws的方式处理[举例]
3)子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型[举例]
4)在throws 过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws
代码演示:
package idea.chapter12.throws_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowsDetail {
public static void main(String[] args) {
f2();
}
//如果没有try-catch 相当于有默认的一个throws ArithmeticException
public static void f2() /*throws ArithmeticException*/ {
//1.对于编译异常,程序中必须处理,比如 try-catch 或者 throws
//2.对于运行时异常,程序中如果没有处理,默认就是throws的方式处理
int n1 = 10;
int n2 = 0;
double res = n1 / n2;
}
public static void f1() throws FileNotFoundException {
//这里调用f3() 报错
//1. 因为f3() 方法抛出的是一个编译异常,而f1()调用了f3()因为f3的异常是一个编译异常所以必须要处理
//2. 就要f1() 必须处理这个编译异常
//3. 在f1() 中,要么 try-catch-finally ,或者继续throws 这个编译异常
f3(); // 抛出异常
}
public static void f3() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("d://aa.txt");
}
public static void f4() {
//1. 在f4()中调用方法f5() 是OK
//2. 原因是f5() 抛出的是运行时异常
//3. 而java中,并不要求程序员显示处理,因为有默认处理机制
f5();
}
public static void f5() throws ArithmeticException {
}
}
class Father { //父类
public void method() throws RuntimeException {
}
}
class Son extends Father {//子类
//3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,
// 所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型
//4. 在throws 过程中,如果有方法 try-catch , 就相当于处理异常,就可以不必throws
@Override
public void method() throws ArithmeticException {
}
}
当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
1)定义类:自定义异常类名(程序员自己写)继承Exception或RuntimeException
2)如果继承Exception,属于编译异常
3)如果继承RuntimeException,属于运行异常(一般来说,继承RuntimeException)
代码演示:
package idea.chapter12.customexception_;
/*
自定义异常
当我们接收Person对象年龄时,要求范围在18-120之间,否则抛出一个
自定义异常(要求 继承RuntimeException),并给出提示信息。
*/
public class CustomException {
public static void main(String[] args) {
int age = 90;
if (!(age > 18 && age < 120)) {
//这里可以用过构造器指定信息
throw new a("你输入的年龄有误");
}
System.out.println("你输入的年龄正确");
}
}
//自定义一个异常
// 1. 一般情况下,我们自定义异常是继承 RuntimeException
//2. 即把自定义异常做成 运行时异常,好处时,我们可以使用默认的处理机制
class a extends RuntimeException {
public a(String message) {
super(message);
}
}
意义 | 位置 | 后面跟的东西 | |
---|---|---|---|
throws | 异常处理的一种方式 | 方法声明处 | 异常类型 |
throw | 手动生成异常对象的关键字 | 方法体中 | 异常对象 |
思路分析:
1.首先我们先调用静态方法methodA() 在该方法中,会先去执行System.out.println("进入方法A");这句话 紧接着我们自己手动制造了一个异常,所以不会继续往下执行,而是先执行finally中的代码 然后在执行catch中的代码,当我们制造了一个异常之后,相当于这个方法就会抛出一个异常,会被exception捕获,所以打印出第三局话 2.因为有我们使用了try-catch 处理了,所以程序不会崩溃,会继续往下执行,所以执行methodB()方法,所以会输出第四句话, System.out.println("进入方法B");因为没有异常,接下来的代码是 return 但是因为finally中代码还没有执行,所以不会先去执行return 而是先执行finally中的代码,再去执行return
package idea.chapter12.throws_;
public class ThrowException {
public static void main(String[] args) {
try {
ReturnExceptionDemo.methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
}
ReturnExceptionDemo.methodB();
}
}
/*
思路分析:
1.首先我们先调用静态方法methodA() 在该方法中,会先去执行System.out.println("进入方法A");这句话 紧接着我们自己手动制造了一个异常,所以不会继续往下执行,而是先执行finally中的代码
然后在执行catch中的代码,当我们制造了一个异常之后,相当于这个方法就会抛出一个异常,会被exception捕获,所以打印出第三局话
2.因为有我们使用了try-catch 处理了,所以程序不会崩溃,会继续往下执行,所以执行methodB()方法,所以会输出第四句话, System.out.println("进入方法B");因为没有异常,接下来的代码是
return 但是因为finally中代码还没有执行,所以不会先去执行return 而是先执行finally中的代码,再去执行return
*/
class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");//1
throw new RuntimeException("制造异常");//3
} finally {
System.out.println("用A方法的finally");//2 因为finally必须被执行所以优先执行finally 在回去抛出异常
}
}
static void methodB() {
try {
System.out.println("进入方法B");//4
return;
} finally {
System.out.println("调用B方法的finally");//5
}
}
}
代码演示:
package idea.chapter12.homework;
/*
1.编程题Homework01.java
a)编写应用程序EcmDef.java,接收命令行的两个参数(整数),计算两数相除。
b)计算两个数相除,要求使用方法cal(int n1,int n2)
c)对数据格式不正确、缺少命令行参数、除0进行异常处理。
*/
public class Homework01 {
public static void main(String[] args) {
try {
if (args.length != 2) {//先判断个数对不对,如果不对手动抛出异常
throw new ArrayIndexOutOfBoundsException("参数个数不对");
}
int n1 = Integer.parseInt(args[0]);
int n2 = Integer.parseInt(args[1]);
//因为cal方法可能会抛出多个异常,所以将可能发生的异常都列出来
double res = cal(n1, n2);
System.out.println("res=" + res);
} catch (ArrayIndexOutOfBoundsException e) {
throw new RuntimeException(e.getMessage());
} catch (NumberFormatException e) {
System.out.println("数据格式不对");
} catch (ArithmeticException e) {
System.out.println("算术异常");
}
}
public static double cal(int n1, int n2) {
return n1 / n2;
}
}
思路分析:
1.第一个可能发生的异常是NullPointerException也就是空指针异常,因为如果我们没有给数组任何数组的话,那么就会抛出空指针异常 2.还可能抛出数组下标越界异常ArrayIndexOutOfBoundsException 因为如果数组的长度如果只要2,但是却访问的是4这个元素 3.还会有一个类型转换异常 因为String和Integer没有任何的关系
package idea.chapter12.homework;
public class Homework02 {
public static void main(String[] args) {
/*
思路分析:
1.第一个可能发生的异常是NullPointerException也就是空指针异常,因为如果我们没有给数组任何数组的话,那么就会抛出空指针异常
2.还可能抛出数组下标越界异常ArrayIndexOutOfBoundsException 因为如果数组的长度如果只要2,但是却访问的是4这个元素
3.还会有一个类型转换异常 因为String和Integer没有任何的关系
*/
//args.length = 0
//这里发生的是 ArrayIndexOutOfBoundsException
//如果数组个数为0会发生数组下标越界异常ArrayIndexOutOfBoundsException
if (args[4].equals("john")) { //如果args[4]为空可能发生NullPointerException
System.out.println("AA");
} else {
System.out.println("BB");
}
Object o = args[2]; //String->Object ,向上转型
Integer i = (Integer) o; //错误,这里一定会发生 ClassCastException 因为无法把一个String转成Integer 违反了向下转型的规则
//**3)要求父类的引用必须指向的是当前目标类型的对象**
}
}
思路分析:
1.程序会先去执行我们的func方法,在该方法中,我们手动的抛出了一个异常,那么相当于我们的func()这个方法有一个异常,就会被catch捕获,但是要注意因为 有finally代码块,因为finally是必须执行的,所以会先输出B 然后因为func方法抛出了异常,那么try中的代码就不会继续往下执行,因此A不会输出 而且是去执行catch中的代码,执行完后,在执行finally中的代码输出C 2.所以最后输出的结果是,B C D
package idea.chapter12.homework;
public class Homework03 {
public static void func() {//静态方法
try {
throw new RuntimeException();
} finally {
System.out.println("B");
}
}
/*
思路分析:
1.程序会先去执行我们的func方法,在该方法中,我们手动的抛出了一个异常,那么相当于我们的func()这个方法有一个异常,就会被catch捕获,但是要注意因为
有finally代码块,因为finally是必须执行的,所以会先输出B 然后因为func方法抛出了异常,那么try中的代码就不会继续往下执行,因此A不会输出
而且是去执行catch中的代码,执行完后,在执行finally中的代码输出C
2.所以最后输出的结果是,B C D
*/
public static void main(String[] args) {//main方法
try {
func();
System.out.println("A");//因为func方法中发生了异常所以这句话不会执行
} catch (Exception e) {
System.out.println("C");
}
System.out.println("D");
}
}
思路分析:
1.首先会去执行我们showExce()方法,因为在该方法中,手动抛出了一个异常,相当于showExce方法有一个异常,就会被catch捕获 所以try中的代码就不会继续往下执行,而是去执行catch中的代码输出B 然后执行finally中的代码,执行完finally中代码,在输出D 2.因为我们的程序使用了try-catch处理 ,因此抛出异常后,程序不会直接崩溃
package idea.chapter12.homework;
public class Homework04 {
public static void main(String[] args) {//main方法
try {
showExce();
System.out.println("A");//因为在showExce()方法中发生了异常所以这句话不会执行
} catch (Exception e) {
System.out.println("B");
} finally {
System.out.println("C");
}
System.out.println("D");
}
/*
思路分析:
1.首先会去执行我们showExce()方法,因为在该方法中,手动抛出了一个异常,相当于showExce方法有一个异常,就会被catch捕获
所以try中的代码就不会继续往下执行,而是去执行catch中的代码输出B 然后执行finally中的代码,执行完finally中代码,在输出D
2.因为我们的程序使用了try-catch处理 ,因此抛出异常后,程序不会直接崩溃
*/
public static void showExce() throws Exception {
throw new Exception();
}
}