在理想的状态下, 用户输入数据的格式永远都是正确的,然而在现实中却充满了不良的数据和带有问题的代码,现在是讨论Java程序设计处理这些问题的机制了
首先是JAVA语言中 异常对象都是派生于Throwable 类的一个实例
Error 类层次结构描述了JAVA运行时内部错误和资源耗尽错误,除了通知用户 其它也无能为力 因此需要注意Exception 层次结构
出现异常该如何解决
1. 出现异常找上级去解决
2. 找上级去解决 相当于找任务的调用者 main的调用者 JVM
3. JVM默认的处理方式
打印异常信息 和错误信息和错误发生的位置
直接停止程序
代码示例:
public class Demo01 {
/*
* 需求
* 1.空指针 NullPointerException
* 2.角标越界 ArrayIndexOutOfBoundsException
* 3.算术异常 ArithmeticException
*/
public static void main(String[] args) {
//ArrayList<String> strings = null;
//strings.add(null);
//访问了一块不属于我的地方
//System.out.println(strings);
int[] a = {1,2};
// System.out.println(a[3]);
System.out.println(10/0);
}
}
try….catch…finally
try 指测试异常代码
catch 指捕获异常信息
finally 指异常结束后要做的事
try.. catch 捕获异常的流程
1.函数中 某句代码 发生异常
2.发生异常 就产生了对应 异常对象
3.这个异常对象 返回给调用者
情况1. 没有对异常进行处理 这时就会把异常交给上级 交给jvm去处理 Jvm使用默认的出来机制
情况2. 调用者进行异常出来(tr…catch) 匹配成功执行catch的语句 程序继续运行
public class Demo02 {
public static void main(String[] args) {
TestException test = new TestException();
int[] arr = new int[4];
try {
// 可能发生异常的代码
System.out.println(arr[5]);
arr = null;
System.out.println(arr[1]);
System.out.println(10/0);
}catch (ArrayIndexOutOfBoundsException e) {
// 再匹配catch的时候 有一个匹配成功就不会再匹配其他catch了
System.out.println("你越界了");
}catch(ArithmeticException e){
// 捕获异常 相当于
// ArithmeticException e = new ArithmeticException("/ zero");
// 小括号中要放 捕获的是什么异常
System.out.println("你除数为0");
}
// 如果要写Exception 来捕获异常 要放到最下面 catch中异常由小到大来写
catch (Exception e) {
System.out.println("代码写错");
}
System.out.println("执行成功!");
}
}
class TestException{
// 除法 返回两个数的商
public int fun(int a, int b) {
// 发生异常 一定会产生一个对应的异常对象
// new ArithmeticException("/ zero");
return a / b;
}
}
finally
- 出现异常与否不会影响到finally的执行
- 也就是说finally一定会执行
- finally的作用 一般用来关闭资源 关闭流 关闭数据库
- final finally finalize 的区别
- final 类不能被继承 变量变常量
- finally(遗言) 异常处理使用
- finalize() 方法 是做垃圾回收用的
class TestFinally{
public int fun() {
int num = 10;
try {
num = 20;
System.out.println(10/0);
return num;
} catch (Exception e) {
num = 30;
// 建立一个返回路径 相当于一个箱子
// 箱子相当于保存的要返回的值
// 不会马上return 会看一下有没有finally
// 有finally就执行 但是不会更改已经在返回路径中的值 再完全return
return num;
}finally {
num = 40;
// finally 只写关闭资源 写return没有意义 会把之前的返回值都覆盖掉
//return num;
}
}
}
public class Demo04 {
public static void main(String[] args) {
// fun1();
TestFinally testFinally = new TestFinally();
int fun = testFinally.fun();
System.out.println(fun);
}
/**
*
*/
public static void fun1() {
try {
System.out.println(10/0);
// 即使直接return方法 finally也会执行
// 直接关闭JVM虚拟机关了就不执行了
} catch (Exception e) {
System.out.println("你除0了");
}finally {
System.out.println("这是我的遗言");
}
System.out.println("我执行了");
}
}
throw 手动抛出异常
/*
* 需求:
* 创建一个人类 有name 和 age
* 要求 人类的年龄赋值时 要在 0 到 120岁之前
* 不用异常
*
*/
public class Demo06 {
public static void main(String[] args) {
Person person = new Person();
person.setName("james");
try {
person.setAge(150);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(person);
}
}
class Person{
private String name;
private int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
// throws关键词 在方法的声明上 标识这个方法可能会抛出异常
// 谁调用这个方法这个异常就会抛给谁
public void setAge(int age) throws Exception {
if (age<=120 && age>=0) {
this.age = age;
}else {
// 手动 抛出一个异常
// throw 后面跟的是抛出的异常对象
//throw new Exception("兄弟 你是龟仙人吗?");
// 抛出自定义异常
throw new AgeOutOfBoundsException("兄弟 你是龟仙人吗?");
}
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
// 自定义类
// 见名知意 跟系统学习
class AgeOutOfBoundsException extends Exception{
/**
* 序列号时候需要使用的ID
*/
private static final long serialVersionUID = 1L;
public AgeOutOfBoundsException() {
// TODO Auto-generated constructor stub
}
public AgeOutOfBoundsException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
// 需要些有参和无参的构造方法
}
Throwable
public class Demo07 {
public static void main(String[] args) {
Exception exception = new Exception("这里可以写错误信息");
// 获取错误信息的方法
String message = exception.getMessage();
//System.out.println(message);
// toString
//System.out.println(exception.toString());
// 打印错误信息 错误的位置 异常类的类名
exception.printStackTrace();
}
}
继承中的异常问题处理
父类没有抛出异常 子类不能抛出异常
如果在子类重写父类方法中 调用了一个有异常的方法 不能抛出异常 只能选择捕获异常
如果父类有抛出编译异常 子类可以不抛出异常也可以抛出异常
异常处理练习题:
/*
* 获取数字的工具类
* 要求:从键盘输入 输入的是字符串要处理异常重新输入
* 封装一个有两个数的对象类
* 要求:类中有两个int数字 作为成员变量
* 封装自定义异常类
* 要求:类名表示除法除数不能为0
* 封装运算类
* 1.获取 两个数的对象
* 2.获取 要做的运算法则 加法或者除法
* 输入数字1是加法 2是除法(输入错误 要重新输入)
* 3.加法方法
* 4.除法方法(要求捕获异常 并抛出自定义异常)
* 5.根据运算法则 执行运算 并返回运算结果
* 除数如果是0 要重新输入数字
* 测试类:
* 对以上方法进行测试
*/
// 创建 Number 类 (省略)
// 创建键盘输入类 NumberTool
public class NumberTool {
private NumberTool() {
// TODO Auto-generated constructor stub
}
public static int InputNumber() {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数字");
String nextLine = scanner.nextLine();
try {
int parseInt = Integer.parseInt(nextLine);
return parseInt;
} catch (Exception e) {
System.out.println("输入有误! 请重新输入");
return InputNumber();
}
}
}
// 创建自定义异常类 DivisorNotAsZeroException
public class DivisorNotAsZeroException extends Exception{
private static final long serialVersionUID = 1L;
public DivisorNotAsZeroException() {
super();
// TODO Auto-generated constructor stub
}
public DivisorNotAsZeroException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
}
// 创建 Operact 类
public class Operact {
// 获得两个数字
public Number getTowNum() {
int inputNumber = NumberTool.InputNumber();
int inputNumber2 = NumberTool.InputNumber();
Number number = new Number(inputNumber, inputNumber2);
return number;
}
// 输入数字选择操作
public String getSelectOperact() {
System.out.println("输入数字1是加法 2是除法(输入错误 要重新输入)");
int num = NumberTool.InputNumber();
if (num == 1) {
return "+";
}else if (num == 2) {
return "/";
}else {
System.out.println("输入有误,请重新输入");
return getSelectOperact();
}
}
// 加法
public int addTowNumber(Number num) {
return num.getNum() + num.getNum1();
}
// 除法
public int divTwoNumber(Number num) throws DivisorNotAsZeroException {
try {
return num.getNum() / num.getNum1();
} catch (Exception e) {
throw new DivisorNotAsZeroException("除数不能为零");
}
}
// 根据传入操作符 进行相应的计算
public int divMethod(String operact, Number num) {
if (operact.equals("+")) {
return addTowNumber(num);
}
try {
return divTwoNumber(num);
} catch (DivisorNotAsZeroException e) {
// TODO Auto-generated catch block
e.getMessage();
System.out.println("输入有误 请重新输入!");
Number number = getTowNum();
return divMethod(operact, number);
}
}
// 启动程序
public void MathTwoNumberStart() {
Operact operact = new Operact();
String selectOperact = operact.getSelectOperact();
Number towNum = operact.getTowNum();
int divMethod = operact.divMethod(selectOperact, towNum);
System.out.println(divMethod);
}
}
// 测试类(省略)