概念
异常:意外、例外
在程序运行过程中,意外发生的情况,背离我们程序本身的意图的表现,都可以理解为异常
错误在我们编写程序的过程中会经常发生,包括编译期间和运行期间的错误
程序中的异常:使用空的对象引用调用方法,数组访问时下标越界,算术运算时除数为0,类型转换时无法正常转型
利用Java中的异常机制,可以更好的提升程序的健壮性
在Java中,通过Throwable及其子类描述各种不同的异常类型
情况一:不正常运行;情况二:中断允许,数据丢失,error
运行时的错误
- 空指针异常:NullPointerException
- 数组下标越界异常:ArrayIndexOutOfBoundsException
- 算术异常:ArithmeticException
- 类型转换异常:ClassCastException
异常分类
- error是程序无法处理的错误,表示运行应用程序中较严重问题
- Exception是程序本身可以处理的异常,异常处理通常指针对这种类型异常的处理。
- unchecked Exception:非检查异常,编译器不要求强制处理的异常
- Checked Exception:检查异常,编译器要求必须处置的异常
异常处理机制
- 抛出异常
- 捕获异常
Java规定:对于可查异常必须捕获、或者声明抛出。允许忽略不可查的RuntimeException(含子类)和Error(含子类)。
五个关键字来实现
try,catch,finally,throw,throws
捕获异常:try(执行可能产生异常的代码)、catch(捕获异常)、finally(无论是否发生异常代码总能执行)
声明异常:throws(声明可能要抛出的异常)
抛出异常:throw(手动抛出异常)
实际应用中的经验与总结
- 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
- 多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
- 对于不确定的代码,可以加上try-catch来处理潜在的异常
- 尽量去处理异常,切记至少简单的调用printStackTrace()去打印输出
- 具体如何处理异常,要根据不同的业务需求和异常类型去决定
- 尽量添加finally语句块去释放占用的资源
try-catch-finally
try块后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。(组合使用)
return
return关键字可以用来完成方法返回值的带回
return关键字用在无返回值方法中终止方法的运行,有返回值的方法中对外提供数据并终止方法的运行
finally权限比return大
throw和throws
可以通过throws声明将要抛出何种类型的异常,通过throw将产生的异常抛出。
如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明出用throws子句来声明抛出异常。
throws语句用在方法定义时声明该方法要抛出的异常类型
当方法抛出异常列表中的异常时,方法将不对这些类型及其子类类型的异常作处理,而抛向调用该方法的方法,由他去处理。
throw用来抛出一个异常,抛出的只能够是可抛出类Throwable或者其子类的实例对象
两个方案:
自定义异常
使用Java内置的异常类可以描述在编程时出现大部分异常情况
也可以通过自定义异常描述特定业务产生的异常类型
自定义异常就是定义一个类,去继承Throwable类或者是它的子类
异常链
捕获一个异常后再抛出另一个异常
将异常发生的原因一个传一个串起来,把底层的异常信息传给上层,逐层抛出。
代码
Scanner input=new Scanner(System.in);
System.out.println("=====运算开始=====");
try {
System.out.print("请输入第一个整数:");
int one=input.nextInt();
System.out.print("请输入第二个整数:");
int two=input.nextInt();
System.out.println("one和two的商是:"+(one/two));
}catch(ArithmeticException e) {
System.exit(1);//无条件终止程序运行
System.out.println("除数不允许为零");
e.printStackTrace();
}catch(InputMismatchException e){
System.out.println("请输入整数");
e.printStackTrace();
}catch(Exception e) {
//多重catch块的最后添加一个异常的父类用它来追踪在前面的子类型中无法捕获的异常信息
System.out.println("程序出错了");
e.printStackTrace();
}finally {
System.out.println("=====运算结束=====");//无论怎样都一定会执行的代码
}
return关键字在异常处理中的作用
return关键字可以用来完成方法返回值的带回
return关键字用在无返回值方法中终止方法的运行,有返回值的方法中对外提供数据并终止方法的运行
finally权限比return大
1、return写在finally里面
2、finally里面不写return
package com.dodoke.test;
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.print("请输入第一个整数:");
int one=input.nextInt();
System.out.print("请输入第二个整数:");
int two=input.nextInt();
return one/two;
}catch(ArithmeticException e) {
System.out.println("除数不允许为零");
return 0;
}finally {
System.out.println("=====运算结束=====");//无论怎样都一定会执行的代码
//return -100000;
}
}
}
package com.dodoke.test;
import java.util.Scanner;
public class TryDemoFour {
public static void main(String[] args) {
//方法1
// testAge();
//方法2
try {
testAge();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*
* throw抛出异常对象的处理方案:
* 1、通过try..catch包含throw语句--自己抛自己处理
* 2、通过throws在方法声明处抛出异常类型--谁调用谁处理--调用者可以自己处理,也可以继续上抛
* 此时可以抛出与throw对象相同的类型或者其父类
*/
// 描述酒店的入住规则:限定年龄,18岁以下,80岁以上的住客必须由亲友陪同
// //方法1
// public static void testAge() {
// 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) {
// e.printStackTrace();
// }
// }
//方法2
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 ArithmeticException();
throw new Exception("18岁以下,80岁以上的住客必须由亲友陪同");
}else {
System.out.println("欢迎入住本酒店");
}
}
}
自定义异常
异常链
package com.dodoke.test;
public class TryDemoFive {
public static void main(String[] args) {
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",e);
}
}
}