JavaSE基础语法--傻瓜笔记--1114(第六章:异常)

第六章:异常

1.Java异常概念

​ 编译时程序写得再好,在运行过程中仍会出现一些问题,导致程序不能正常运行,这就是异常

​ 注:开发过程中的语法错误逻辑错误不是异常。

Java中的发生的异常(广义:一切的不正常)事件分为两类:

​ ①Error:Java虚拟机无法解决的问题,如JVM内部错误,资源耗尽等。这种错误一般不编写针对性的代码进行处理。

​ ②Exception:其它因编程错误或偶然的外在因素导致的一般性问题。可以使用针对性的代码进行处理。(使用Java语言的异常处理机制,可以控制,后面代码可以继续执行的。)

​ 例如:空指针异常

​ 数组下标越界

​ 试图读取不存在的文件

​ 网络连接中断

狭义的异常:

​ 对于这些异常有两种解决方法:①遇到异常就终止程序的运行②由程序员在编写程序时,就考虑到异常的检测,异常消息的提示,以及异常的处理。

​ 捕获异常最理想的时期是在编译期间

​ 这些异常又分为编译异常,和 运行异常

常见异常
Error:

​ 当内存不够时,或抛出错误,称为Error

 		// jvm内存耗光      Error
        List list = new ArrayList();
        while(true){
            list.add(new Random());
        }
Exception:
        // 数组下标越界
        // java.lang.ArrayIndexOutOfBoundsException
        int[] a = new int[4];
        a[5] = 1;
        // 算术异常
        // java.lang.ArithmeticException
        int a = 10;
        int b = 0;
        System.out.println(a/b);
        // 类类转换异常
        // java.lang.ClassCastException
        String s = "12";
        Object obj = s;
        Integer i = (Integer)obj;
        // 数字格式化异常
        // java.lang.NumberFormatException
        int i = Integer.parseInt("a");
        // 空指针异常
        // java.lang.NullPointerException
        String s = null;
        s.length();

2.异常的体系

​ Throwable类有两个直接子类:Error类,Exception类。Exception表示异常,是所有异常类的父类,是程序员关心的。Error表示错误,可能是编译期错误或者系统错误。

​ 异常又分为:

​ ①运行期异常:所有RuntimeException的子类都是运行期异常。

​ ②编译期异常(Checked Exception):除去运行期的异常都是编译期异常。编译期异常的层次和RuntimeException是同一层次的编译期异常出现就需要处理。ParseException(解析异常)属于编译期异常。

3.异常处理

​ Jvm默认异常处理方式:

​ ① 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
​ ②程序停止运行

3.1try-catch
        // java编程语言使用异常处理机制为程序提供了错误处理的能力
        // 步骤:① 程序中预先设置好处理异常的方法   ② 程序运行  ③异常出现
        //          ④处理异常  ⑤ 处理完毕,继续执行下面的语句
        // try{
        //   将可能出现的代码放入其中 : 代码范围尽可能地小
        //   }catch(异常类型  异常名){
        //      异常处理语句
        //   }
        // try中出现异常,然后执行catch,再执行下面地语句
①正常格式
        int c = 5;
        int d = 0;
        try{
            System.out.println(c/d);
        }catch(ArithmeticException ex){
            System.out.println("除数不能为0");
        }
        System.out.println("处理完异常,继续执行下面地语句");
    }
②嵌套方式
			// 嵌套式 try catch
        try {
            // 如果外层地 try catch异常,那么会越过内层try catch,执行相对应地catch,然后继续执行下面的语句
            int f = 10;
            int g = 2;
            System.out.println(f / g);
            try {
                // 如果内层的异常,那也就意味着外层的是正常的。
                // 因此会执行内层的相对应的catch,然后越过外层的catch,继续执行下面的语句
                Integer.parseInt("abc");
            } catch (NumberFormatException num1) {
                System.out.println("数值格式化异常");
            }
        } catch (ArithmeticException ari1) {
            System.out.println("算术异常");
        }
③一个try对应多个catch
        // 一个try 对应多个 catch
        try {
            // 如果语句1 异常,那么就会越过语句2,直接执行对应地catch,之后会执行下面地语句
            int a = 10;
            int b = 0;
            System.out.println(a/b);

            int c = 10;
            int d = 2;
            System.out.println(c / d);
            // 如果上面地正常,此语句出错,那么就会执行对应地catch,然后继续执行下面地语句
            Integer.parseInt("abc");

            System.out.println("如果上面语句有异常,那么此语句不会被执行");
        } catch (ArithmeticException ari) {
            System.out.println("算术异常");
        } catch (NumberFormatException num) {
            System.out.println("数值格式化异常");
        } catch (Exception ex) {// 如果不知道具体的异常类型,就可以使用这个。
            // 这是一个大范围的异常捕获,因此用的时候需要放在最下面
            System.out.println("系统忙");// 用户看的
            System.out.println(ex.getMessage());// 程序员看的
            // 后期可以通过第三方日志组件向文件中输出信息。
        }
        System.out.println("处理完异常继续执行");
    }
3.2finally

​ 不管是否出现异常,并且异常是否被处理都会执行finally,结束之前优先执行finally

①捕获中有return
 	// 捕获中有return,还是会执行finally语句之后再返回状态码
    public static int test(){
        try{
            int a = 10;
            int b = 0;
            System.out.println(a/b);
        }catch(ArithmeticException ari){
            System.out.println("算术运算异常");
            return 0;// 状态码
        }finally{
            System.out.println("FINALLY无论如何都会执行");
        }

        System.out.println("并不会被执行");
        return 1;
    }
②如果finally 中有return

在正常情况(即程序正常执行try catch finally语句块,不会在语句中出现退出程序、线程终止等特殊情况)下,都会执行finally语句块,如果finally中有return,则程序会走finally中的return,如果没有,则先执行try或者catch中的return,将其存入临时栈中,执行完finally语句后才返回临时栈中的值

    // 如果finally 中有return,那么后面就不能再写语句了。因为最终的return已经在finally中了。
    // 那么如果有异常的话,那么catch中的return会被finally中的return覆盖
    public static int test1(){
        try{
            int a = 10;
            int b = 0;
            System.out.println(a/b);
        }catch(ArithmeticException ari){
            System.out.println("算术运算异常");
            return 0;
        }finally{
            System.out.println("FINALLY无论如何都会执行");
            return 2;
        }
    }
③如果有异常,但是没有catch处理
// 如果有异常,但是没有catch处理,那么就会在执行完finally后抛出异常,终止后面程序的执行
    public static int test2(){
        try{
            int a = 10;
            int b = 0;
            System.out.println(a/b);
        }finally{
            System.out.println("FINALLY无论如何都会执行");
        }

        System.out.println("并不会被执行");
        return 1;
    }
3.3throws
throws:

​ 定义方法时 声明 可能出现的变量,此方法可以不处理,交给方法调用处处理

​ 一个方法可以声明多个异常

 public static void main(String[] args) throws ParseException{
        SimpleDateFormat s1 = new SimpleDateFormat();
        // 这个是编译期异常,但是不用捕获的原因是,这个声明只是为了声明父类方法中的throw创建的异常对象
        s1.parse("2020-11-12-ww");// 需要抛出异常
        int a = 10;
        int b = 0;
        chu(a,b);

        try{
            test();
        }catch(ParseException par){
            System.out.println("编译期异常可以不立即处理,但是到达顶层后就必须处理");
        }
    }

    // throws 声明此方法可能出现算术异常,如果throws抛出的是一个运行期异常,那么可以处理也可以不处理
    public static void chu(int a, int b) throws ArithmeticException{
        System.out.println(a/b);
    }

    // 如果throws声明的是一个编译期异常,可以立即处理
    // 也可以不立即处理,但是一旦抛到顶层方法中,就必须处理
    public static void test1() throws ParseException{
        System.out.println("编译期异常");
    }

    public static void test() throws ParseException{
        test1();
    }
任何方法都可以通过throws 声明异常,包括抽象方法

​ 父类

/*
* 任何方法都可以通过throws 声明异常,包括抽象方法
* */
public abstract class AnomalyDemo6 {
    public abstract void eat() throws ParseException;
    public abstract void sleep() throws ArithmeticException;
}

​ 子类

/*
* 子类重写父类方法时,也要声明父类异常
* 但是子类方法不能声明抛出比父类类型更大的异常(运行期影响不大)
* */
public class Demo6child extends AnomalyDemo6{
    @Override
    public void eat() throws ParseException {

    }

    @Override
    public void sleep() throws RuntimeException {
    // 这里可以使用RuntimeException的原因是,RuntimeException包含ArithmeticException
        // 不能使用Exception 的原因是,Exception不仅包含RuntimeException,还包含其他的异常
        // 子类声明RuntimeException,绝对可以找到父类的异常类型,
        // 但是如果子类声明Exception,就不一定可以找到父类的异常类型。
    }
}
3.4throw

​ throw用于显式抛出异常,在程序中主动抛出异常对象,在构造方法中可以传入异常原因

​ throw语句可以单独使用,

​ throw语句执行的不是异常类,而是一个异常实例,而且每次只能执行一次throw语句抛出异常对象后,后面的语句不会再执行。
throw如果创建的是一个编译期的对象,要么用try catch捕获,要么用throws声明异常

public class AnomalyDemo7 {
    public static void test(int a){
        if(a<0 | a>100){
            throw new RuntimeException("不在合法范围");
        }
        System.out.println("zhenqu");
    }
}
3.5自定义异常

​ 自定义异常类: 需要继承RuntimeException(运行期)或者Exception(编译期)才能称为异常类。

​ 在我们写程序的过程中出现一些不满足条件的情况时,也可以自定义异常类,来表示某种情况。

public class SroceException extends Exception{
    public SroceException() {
    }

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

​ 调用类

public class AnomalyDemo8 {
    public static void main(String[] args) {
        try{
            fenShu(101);
        }catch(SroceException s){
            s.printStackTrace();
            System.out.println(s.getMessage());
        }
    }

    public static void fenShu(int a) throws SroceException{
        if(a<0 | a>100){
            throw new SroceException("分数不合法");
        }
    }
}

若有错误,欢迎私信指正。

你可能感兴趣的:(笔记,java)