Java异常处理详解

Throwable

Throwable 异常最顶端的类
    Error 服务器崩溃 数据库崩溃
    Exception 异常类 
        RuntimeException 运行时异常

出现异常如何解决
找任务的调用者(出现异常找上级去解决),比如main函数的调用者JVM去处理
JVM默认的处理方式:打印异常类的错误信息和错误发生的位置,直接停止程序

几种常见异常:
         1.空指针异常
         NullPointerException
         访问了一块本不属于我的空间
         2.角标越界异常
         ArrayIndexOutOfBoundsException
         3.算术异常
         ArithmeticException

try…catch

try   指测试异常代码
catch 指捕获异常信息

try...catch 捕获异常的流程
    1.函数中某句代码发生异常
    2.发生异常就产生了对应异常对象
    3.这个异常对象返回给调用者
        情况一:没有对异常进行处理这时就会把异常交给JVM(交给上级)去处理,jvm使用了默认的处理方式
        情况二:调用者进行了异常处理(try...catch),这时 返回的异常对象会跟catch进行匹配,匹配成功执行catch中的语句,程序继续运行

代码示例:
        // 测试异常
        class TestException {
            // 除法 返回两个数的商
            public int fun(int a, int b) {
                // 发生异常一定会产生一个对应的异常对象
                // new ArithmeticException("/ by zero")
                return a / b;
            }
        }

        public static void main(String[] args) {
            TestException testException = new TestException();
            try {
                // 可能发生异常的代码
                int num = testException.fun(10, 2);
                System.out.println(num);
            } catch (ArithmeticException e) {
                // 捕获异常
                // ArithmeticException e = new ArithmeticException();
                // 小括号中要放捕获是什么异常
                System.out.println("你除数是0");
            }
            System.out.println("你猜我执行了吗");
        }

多catch处理异常

处理空指针 角标越界 算术异常

        int[] array = new int[4];
        try {
            // 越界异常 产生越界异常对象 
            // new ArrayIndexOutOfBoundsException
            System.out.println(array[5]);
            array = null;
            System.out.println(array[1]);
            System.out.println(10 / 0);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("你越界了");
        } catch (NullPointerException e) {
            System.out.println("空指针");
        } catch (ArithmeticException e) {
            System.out.println("除0");
        }
        System.out.println("你猜我执行了吗");

注意:在匹配catch的时候有一个被匹配上,其他的catch 就不会被匹配;如果catch中要写Exception来捕获异常,要放到最下面并且catch中异常由小到大

finally

finally作用:一般用来关闭资源、关闭流、关闭数据库
注意:出现异常与否不会影响到finally的执行,也就是说 finally一定会执行

finally 实例1try {
            System.out.println(10 / 0);
            // 即使直接return方法 finally也会执行
            return;
        } catch (Exception e) {
            System.out.println("➗0");
        } finally {
            System.out.println("这是我的遗言");
        }
        System.out.println("你猜我执行了吗");

finally 实例2:
        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就执行但是不会更改已经在返回路径中的值
                     * 等finally执行完了再完全return
                     */
                    return num;
                } finally {
                    num = 40;
                    // 注意:finally中只写关闭资源 写return没有意义,会把之前的返回值都覆盖
                }
            }
        }

编译时异常

编译时异常就是为了这个可能的错误做的提前准备
编译时异常:系统强制你要处理 try 或者 抛出异常
例如:
    FileInputStream inputStream = new FileInputStream("wl.txt");
    读取该路径下的文件,相当于系统不知道这个路径有没有文件,需要提前询问如果没有这个路径下的文件你如何去处理。
    处理方式一 添加try...catch(自己来处理)
        try {
            FileInputStream inputStream = new FileInputStream("wl.txt");
        } catch (FileNotFoundException e) {
            System.out.println("没有这个文件");
        }
    处理方式二 可以把问题抛给main函数,然后在main函数的函数声明上添加throws要抛出的异常类名
        public static void main(String[] args) throws FileNotFoundException  {
            FileInputStream inputStream = new FileInputStream("wl.txt");
       }

运行时异常

运行时异常(RuntimeException):
1.抛出运行时异常,方法的声明上可以不用throws来标识
2.可以不对运行时异常进行处理
    1)处理程序可以继续执行
    2)不处理程序就直接停止
当方法中抛出运行时异常说明如果发生了该异常就需要停掉程序,让程序再执行下去没有意义
例如:
    class Test{
        // 抛出运行时异常
        public void fun1(){
            throw new RuntimeException();
        }

        // 计算圆面积
        public double fun2(double r) {
            // 如果半径小于等于0那么接下去运算将没有意义,这时可以抛出运行时异常来停止程序修改代码
            if (r <= 0) {
                throw new RuntimeException("半径不对");
            }
            return r * r * Math.PI; 
        }
    }

    public static void main(String[] args) {
        Test test = new Test();
        // test.fun1();
        // 测试圆面积
        double fun2 = test.fun2(0);
        System.out.println(fun2);
    }

自定义异常

自定义异常:类名要见名知意并且跟系统学习
例如:
    class AgeOutOfBoundsException extends Exception{
        /**
         * 序列化时使用的id
         */
        private static final long serialVersionUID = 1L;
        // 写有参 和 无参构造方法
        public AgeOutOfBoundsException() {
            super();
        }
        public AgeOutOfBoundsException(String message) {
            super(message);
        }   
    }

    // throws关键词在方法的声明上标识这个方法可能会抛出异常,谁调用这个方法这个异常就抛给谁
    public void setAge(int age) throws Exception {
        // 需要在这个范围内才给age赋值
        if (age >=0 && age <= 120) {
            this.age = age;
        } else {
            // 手动抛出一个异常,throw后面跟的是抛出的异常对象
            // throw new Exception("你是��吗");
            // 抛出自定义异常
            throw new AgeOutOfBoundsException("你是��吗");
        }
    }

Throwable 中的方法

    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();
    }
打印结果
        // getMessage()
        这里可以写错误信息

        // toString
        java.lang.Exception: 这里可以写错误信息

        // printStackTrace()
        java.lang.Exception: 这里可以写错误信息
                at com.lanou3g.Demo07.main(Demo07.java:7)

继承中 方法重写异常

1.如果父类没有抛出编译异常,子类不能抛出编译异常
2.如果在子类重写父类的方法中调用了一个有异常的方法,这时只能选择 try ... catch处理,不能抛出异常
3.如果父类有抛出编译异常,子类可以不抛出异常也可以抛出异常
代码实例:
        // 父类
        class Father {
            public void fun(){

            }
        }
        // 子类
        class Son extends Father{
            @Override
            public void fun() {
                try {
                    method();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            // 带异常的方法
            public void method() throws Exception {

            }
        }

异常处理练习

需求:无限输入整数存放到集合中打印 输入quit停止 希望在输入字符串的时候让程序也能继续运行

    public static void main(String[] args) {
        ArrayList list = new ArrayList<>();
        Scanner scanner = new Scanner(System.in);
        while (true) {
                String string = scanner.nextLine();
                if (string.equals("quit")) {
                    break;
                }
                // 处理异常
                try {
                    int num = Integer.parseInt(string);
                    list.add(num);
                } catch (Exception e) {
                    System.out.println("输入错误");
                }   
        }
        System.out.println(list);
    }
/*
 * 获取数字的工具类
 * 要求:从键盘输入 输入的是字符串要处理异常重新输入
 */
    public class IntTools {
        // 构造方法私有化
        private IntTools() {

        }
        public static int getIntNum() {
            System.out.println("请输入一个数");
            Scanner scanner = new Scanner(System.in);
            String string = scanner.nextLine();
            try {
                int num = Integer.parseInt(string);
                return num;
            } catch (Exception e) {
                // 再次调用本方法 进行数字输入
                return getIntNum();
            }

        }
    }

/*
 * 封装一个有两个数的对象类
 * 要求:类中有两个int数字 作为成员变量
 */
    public class MyNum {
        private int num1;
        private int num2;
        public MyNum() {
            super();
        }
        public MyNum(int num1, int num2) {
            super();
            this.num1 = num1;
            this.num2 = num2;
        }
        public int getNum1() {
            return num1;
        }
        public void setNum1(int num1) {
            this.num1 = num1;
        }
        public int getNum2() {
            return num2;
        }
        public void setNum2(int num2) {
            this.num2 = num2;
        }   
    }

/*
 * 封装自定义异常类
 * 要求:类名表示除法除数不能为0 
 */
    public class DivNotZeroException extends Exception{

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        public DivNotZeroException() {
            super();
        }

        public DivNotZeroException(String message) {
            super(message);
        }

    }

/*
 * 封装运算类
 * 1.获取 两个数的对象
 * 2.获取 要做的运算法则 加法或者除法 
 *   输入数字1是加法 2是除法(输入错误 要重新输入)
 * 3.加法方法
 * 4.除法方法(要求捕获异常 并抛出自定义异常)
 * 5.根据运算法则 执行运算 并返回运算结果
 *   除数如果是0 要重新输入数字
 */
    public class Operation {
        // 获取两个数的对象
        public MyNum getNum() {
            int num1 = IntTools.getIntNum();
            int num2 = IntTools.getIntNum();
            MyNum myNum = new MyNum(num1, num2);
            return myNum;
        }
        // 获取运算法则
        public String getMethod() {
            System.out.println("输入数字1是加法 2是除法(输入错误 要重新输入)");
            int num = IntTools.getIntNum();
            // 判断数字返回要做的运算
            if (num == 1) {
                return "+";
            } else if(num == 2) {
                return "/";
            } else {
                return getMethod();
            }
        }
        // 加法
        public int sum(MyNum myNum) {
            return myNum.getNum1() + myNum.getNum2();
        }
        // 除法 要求捕获异常 并抛出自定义异常
        public int div(MyNum myNum) throws DivNotZeroException {
            try {
                return myNum.getNum1() / myNum.getNum2();
            } catch (Exception e) {
                // 获取到这个异常 但是不处理
                // 交给方法的调用者去处理
                throw new DivNotZeroException("被除数不能为0");
            }   
        }
        // 根据运算法则 执行运算
        public int getResultByOperationAndNum(String operation,MyNum myNum) {
            // 判断操作符 去做相应的运算
            if (operation.equals("+")) {
                return sum(myNum);
            }
            // 除法 如果报了异常 除数是0的时候
            // 需要重新输入那两个数
            try {
                return div(myNum);
            } catch (DivNotZeroException e) {
                System.out.println(e.getMessage());
                System.out.println("请重新输入两个数:");
                // 重新调用获取两个数对象的方法
                MyNum newNum = getNum();
                // 重新调用运算的方法 进行运算
                return getResultByOperationAndNum(operation, newNum);
            }
        }
    }
/*   
 * 测试类:
 * 对以上方法进行测试
 */
    public class Test {
        public static void main(String[] args) {
            Operation operation = new Operation();
            // 获取运算符
            String method = operation.getMethod();
            // 获取两个数的对象
            MyNum num = operation.getNum();
            int result = operation.getResultByOperationAndNum(method, num);
            System.out.println(result);
        }
    }

你可能感兴趣的:(Java异常处理详解)