什么是异常:本质上是程序上的错误,包括编译时错误和运行间错误
异常的分类:
Throwable:java中异常的根类
Error:程序无法处理的错误,在程序的控制和处理能力之外,一般是java虚拟机出现了问题
Exception:程序本身可以处理的异常,异常处理通常指针对这一类型异常
非检查异常:编译器不要求强制处理的异常
检查异常:编译器要求必须处理的异常
如何处理异常:
•try-catch-finally
•throw
•throws
•自定义异常
•异常链
异常处理机制: 抛出异常 捕获异常
抛出异常:当一个方法出现错误引发异常的时候,方法会创建异常对象,并将其交付给运行时系统
捕获异常:运行时系统会寻找合适的异常处理器,找到后执行相对应的异常处理逻辑,否则系统将会中止
对异常的处理分为两种方式,
方式1:
try-catch-finally:
try:用于捕获异常,try后可接0个或多个catch块,如果没有catch块,则必须接finally块,不允许单独使用
catch和finally如果没有try的加入,是不可连接的
catch:用于处理try捕获到的异常
finally:无论是否发生,异常代码总能执行
案例测试:
package com.imooc.test;
import java.util.Scanner;
public class TryDemoOne {
public static void main(String[] args) {
//要求:定义两个整数,接受用户的输入,输出两数之商
Scanner input = new Scanner(System.in);
System.out.println("=====运算开始======");
try{
System.out.println("请输入第一个整数:");
int one = input.nextInt();
System.out.println("请输入第二个整数:");
int two = input.nextInt();
System.out.println("one和two的商:"+(one/two));
}catch(Exception e) {
System.out.println("程序出错");
e.printStackTrace();//输出异常类型信息
}finally{
System.out.println("=====运算结束======");
}
}
}
测试:
=====运算开始======
请输入第一个整数:
12
请输入第二个整数:
0
程序出错
=====运算结束======
java.lang.ArithmeticException: / by zero
at com.imooc.test.TryDemoOne.main(TryDemoOne.java:21)
使用多重catch结构处理异常:针对不同的异常有不同的处理方式
多重catch语句的异常捕获,捕获的顺序和catch语句的执行顺序有关,当捕获到了一个异常时,剩下的catch语句就不再进行匹配
代码如下:
package com.imooc.test;
import java.util.InputMismatchException;
import java.util.Scanner;
public class TryDemoOne {
public static void main(String[] args) {
//要求:定义两个整数,接受用户的输入,输出两数之商
Scanner input = new Scanner(System.in);
System.out.println("=====运算开始======");
try{
System.out.println("请输入第一个整数:");
int one = input.nextInt();
System.out.println("请输入第二个整数:");
int two = input.nextInt();
System.out.println("one和two的商:"+(one/two));
}catch(ArithmeticException e) {
System.out.println("除数不允许为0~~");
e.printStackTrace();
}catch(InputMismatchException e) {
System.out.println("请输入整数");
e.printStackTrace();
}catch(Exception e) {
//捕获前两个catch不能捕获的异常,放在最后一个
System.out.println("程序出错~~");
e.printStackTrace();
}finally{
System.out.println("=====运算结束======");
}
}
}
测试1:
=====运算开始======
请输入第一个整数:
12
请输入第二个整数:
0
除数不允许为0~~
java.lang.ArithmeticException: / by zero
=====运算结束======
at com.imooc.test.TryDemoOne.main(TryDemoOne.java:22)
测试2:
=====运算开始======
请输入第一个整数:
12
请输入第二个整数:
a
请输入整数
java.util.InputMismatchException
=====运算结束======
at java.util.Scanner.throwFor(Scanner.java:864)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
at com.imooc.test.TryDemoOne.main(TryDemoOne.java:21)
测试3:
其余的异常会被Exception捕获
中止finally执行的方法:
在什么情况下可以强制中止finally执行:通过System.exit(int a)方法,参数a设置为 非0 即可
catch(ArithmeticException e) {
//中止程序运行,参数为 非0 即可,表示程序无条件中止运行
System.exit(1);
System.out.println("除数不允许为0~~");
e.printStackTrace();
}
return关键字在异常处理中的作用:
package com.imooc.test;
import java.util.InputMismatchException;
import java.util.Scanner;
public class TryDemoTwo {
public static void main(String[] args) {
int result = test();
System.out.println("one和two的商:" + result);
}
public static int test() {
// 要求:定义两个整数,接受用户的输入,输出两数之商
Scanner input = new Scanner(System.in);
System.out.println("=====运算开始======");
try {
System.out.println("请输入第一个整数:");
int one = input.nextInt();
System.out.println("请输入第二个整数:");
int two = input.nextInt();
return one / two;
} catch (ArithmeticException e) {
//算术异常捕获块
System.out.println("除数不允许为0~~");
return 0;
} finally {
System.out.println("=====运算结束======");
return -100000;
}
}
}
测试结果:
=====运算开始======
请输入第一个整数:
36
请输入第二个整数:
6
=====运算结束======
one和two的商:-100000
finally块里的return会强制覆盖掉前面的return
方式2:
使用throw和throws实现异常处理:
•可以通过throws声明要抛出何种类型的异常,通过throw将产生的异常抛出
代码:
package com.imooc.test;
import java.util.InputMismatchException;
import java.util.Scanner;
public class TryDemoThree {
public static void main(String[] args) {
try {
int result = test();//既然在这里调用且有可能发生异常,则进行捕获,否则继续向上抛出
System.out.println("one和two的商:" + result);
} catch (ArithmeticException e) {
System.out.println("除数不允许为0~~");
} catch (InputMismatchException e) {
System.out.println("请输入整数");
} catch (Exception e) {
}
}
// 通过throws抛出异常时,针对可能出现的多种异常情况,解决方案:
// 1、throws后面接多个异常类型,中间用逗号分割
// 2、在throws后接Exception
/**
* 测试接收数据相除结果的商的方法
* @return 两个接收数据的商
* @throws ArithmeticException
* @throws InputMismatchException
*/
public static int test() throws ArithmeticException,InputMismatchException{
// 要求:定义两个整数,接受用户的输入,输出两数之商
Scanner input = new Scanner(System.in);
System.out.println("=====运算开始======");
System.out.println("请输入第一个整数:");
int one = input.nextInt();
System.out.println("请输入第二个整数:");
int two = input.nextInt();
System.out.println("=====运算结束======");
return one / two;
}
}
输出结果1:
=====运算开始======
请输入第一个整数:
12
请输入第二个整数:
0
=====运算结束======
除数不允许为0~~
输出结果2:
=====运算开始======
请输入第一个整数:
12
请输入第二个整数:
a
请输入整数
使用throw抛出异常对象:throw用来抛出一个异常,throw抛出的只能是类Throwable或者其子类的实例对象
可以用来 回避可能存在的风险,完成一些程序的逻辑
两种使用方式:
方式1:
package com.imooc.test;
import java.util.Scanner;
public class TryDemoFour {
// throw抛出异常的解决方案:
// 1、通过try...catch包含throw语句--自己抛出,自己处理
// 酒店入住规则:限定年龄,18岁以下和80岁以上必须有亲友陪同入住
public static void testAge() {
// 判断年龄是否达到要求
// 1、通过try...catch包含throw语句--自己抛出,自己处理
try {
System.out.println("请输入年龄:");
Scanner input = new Scanner(System.in);
int age = input.nextInt();
if (age < 18 || age > 80) {
throw new Exception("18岁以下和80岁以上必须有亲友陪同入住");
} else {
System.out.println("欢迎入住");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
testAge();
}
}
方式2:
package com.imooc.test;
import java.util.Scanner;
public class TryDemoFour {
// throw抛出异常的解决方案:
// 2、通过throws在方法声明处抛出异常类型--谁调用谁处理--调用者可以自己处理,也可以继续上抛
public static void testAge() throws Exception {
// 判断年龄是否达到要求
System.out.println("请输入年龄:");
Scanner input = new Scanner(System.in);
int age = input.nextInt();
if (age < 18 || age > 80) {
throw new Exception("18岁以下和80岁以上必须有亲友陪同入住");
} else {
System.out.println("欢迎入住");
}
}
public static void main(String[] args) {
try {
testAge();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
两种方式的输出结果:
请输入年龄:
8
java.lang.Exception: 18岁以下和80岁以上必须有亲友陪同入住
at com.imooc.test.TryDemoFour.testAge(TryDemoFour.java:18)
at com.imooc.test.TryDemoFour.main(TryDemoFour.java:42)
自定义异常:通过自定义异常来描述特定业务产生的异常类型,定义一个类,去继承Throwable类或者他的子类
自定义异常代码:
package com.imooc.test;
public class HotelAgeException extends Exception {
public HotelAgeException() {
super("18岁以下和80岁以上必须有亲友陪同入住");
}
}
测试代码:
package com.imooc.test;
import java.util.Scanner;
public class TryDemoFour {
public static void testAge() throws HotelAgeException{
// 判断年龄是否达到要求
System.out.println("请输入年龄:");
Scanner input = new Scanner(System.in);
int age = input.nextInt();
if (age < 18 || age > 80) {
//throw new Exception("18岁以下和80岁以上必须有亲友陪同入住");
throw new HotelAgeException();
} else {
System.out.println("欢迎入住");
}
}
public static void main(String[] args) {
try {
testAge();
} catch (HotelAgeException e) {
System.out.println(e.getMessage());
System.out.println("酒店工作人员不允许办理登记");
}catch(Exception e) {
e.printStackTrace();
}
}
}
输出结果:
请输入年龄:
8
18岁以下和80岁以上必须有亲友陪同入住
酒店工作人员不允许办理登记
异常链:在捕获一个异常后再抛出另外一个异常
代码:
package com.imooc.test;
public class TryDemoFive {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
testThree();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void testOne() throws HotelAgeException {
throw new HotelAgeException();
}
public static void testTwo() throws Exception{
try {
testOne();
} catch (HotelAgeException e) {
throw new Exception("我是新产生的异常1",e);
}
}
public static void testThree() throws Exception {
try {
testTwo();
} catch (Exception e) {
Exception e1 = new Exception("我是新产生的异常2");
e1.initCause(e);
throw e1;
//throw new Exception("我是新产生的异常2");
}
}
}
输出结果:
java.lang.Exception: 我是新产生的异常2
at com.imooc.test.TryDemoFive.testThree(TryDemoFive.java:31)
at com.imooc.test.TryDemoFive.main(TryDemoFive.java:8)
Caused by: java.lang.Exception: 我是新产生的异常1
at com.imooc.test.TryDemoFive.testTwo(TryDemoFive.java:23)
at com.imooc.test.TryDemoFive.testThree(TryDemoFive.java:29)
... 1 more
Caused by: com.imooc.test.HotelAgeException: 18岁以下和80岁以上必须有亲友陪同入住
at com.imooc.test.TryDemoFive.testOne(TryDemoFive.java:16)
at com.imooc.test.TryDemoFive.testTwo(TryDemoFive.java:21)
... 2 more
总结: