Java 异常处理全解析

在理想的状态下, 用户输入数据的格式永远都是正确的,然而在现实中却充满了不良的数据和带有问题的代码,现在是讨论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);  
    }   
}
// 测试类(省略)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值