20.异常

  • 3.异常

    3.1 异常(记忆)

    • 异常的概述

      异常就是程序出现了不正常的情况

    • 注意:语法错误不能算在异常体系中
    • 异常的体系结构

       

      3.2 编译时异常和运行时异常的区别(记忆)

      • 编译时异常

        • 都是Exception类及其子类

        • 必须显示处理,否则程序就会发生错误,无法通过编译

      • 运行时异常

        • 都是RuntimeException类及其子类

        • 无需显示处理,也可以和编译时异常一样处理

图示 

 

3.3 JVM默认处理异常的方式(理解)

  • 如果程序出现了问题,我们没有做任何处理,最终JVM 会做默认的处理,处理方式有如下两个步骤:

    • 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台

    • 程序停止执行

package com.itheima.exce;

import java.text.ParseException;
import java.text.SimpleDateFormat;

public class ExceptionDemo1 {
    public static void main(String[] args) throws ParseException {
        //思考:控制台为什么会有这样的红色字体呢》是谁打印的?
        int [] arr={1,2,3,4,5};
        System.out.println(arr[10]);//当代码出现了异常,那么就在这里创建了一个异常对象
                                    //new ArrayIndexOutOfBoundsException();
                                    //首先会看程序中有没有自己处理异常的代码
                                    //如果没有,交给本方法的调用者处理
                                    //最终这个异常会交给虚拟机默认处理
                                    //JVM默认处理异常做了那几件事情
                                    //1.将异常信息以红色信息展示在控制台上
                                    //2.停止程序运行,----哪里出现了异常,程序在哪里停止,下面的代码不执行
        System.out.println("啊哈哈哈");
        //ArrayIndexOutOfBoundsException
//        String s=null;
//        System.out.println(s.equals("嘿嘿"));//NullPointerException
//        SimpleDateFormat sdf=new SimpleDateFormat("yyy年MM月dd日");
//        sdf.parse("2048-1月1日");//ParseException
    }
}

3.4 查看异常信息 (理解)

控制台在打印异常信息时,会打印异常类名,异常出现的原因,异常出现的位置

我们调bug时,可以根据提示,找到异常出现的位置,分析原因,修改异常代码

阅读异常信息的练习

阅读单个方法中出现的异常

package com.itheima.exce;

import javax.swing.plaf.IconUIResource;
import java.util.ArrayList;
import java.util.Iterator;

public class ExceptionDemo3 {
    //创建一个ArrayList集合,添加一些元素"aaa","bbb","ccc","bbb","bbb" null
    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("bbb");
        list.add("ccc");
        list.add("bbb");
        list.add(null);
        int count=0;
        Iterator <String> iterator=list.iterator();
        while (iterator.hasNext()) {
            if ("bbb".equals(iterator.next())) {
                count++;
            }
        }
        System.out.println("在集合中一共出现bbb有"+count);
        }
}

  

阅读多个方法中出现的异常 

package com.itheima.exce;

public class ExceptionDemo4 {
    public static void main(String[] args) {
        //定义一个方法,用来遍历数组
        //int []arr={1,2,3,4,5};
        int []arr=null;
        printArr(arr);
        
    }

    private static void printArr(int[] arr) {
        if (arr != null) {
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i]);
            }
        }

    }


}

  阅读多个类方法中出现的异常  

 

小结:

1.异常就是程序出现不正常的情况

2.异常的两类?

  编译时异常,运行时异常

3.虚拟机默认处理异常的方式?

  将异常信息以红色字体打印在控制台,结束程序运行

3.5 throws方式处理异常(应用)

 

定义格式

public void 方法() throws 异常类名 {
   
}

注意:这个格式时写在方法的定义处,表示声明一个异常

 

示例代码

package com.itheima.exce;


import java.text.ParseException;
import java.text.SimpleDateFormat;

public class ExceptionDemo6 {
    public static void main(String[] args) throws ParseException {
        method1(); //此时调用者也没有处理.还是会交给虚拟机处理.
        method2(); //还是继续交给调用者处理.而main方法的调用者是虚拟机还是会采取虚拟机默认处理异常的方法.
    }

    //告诉调用者,你调用我,有可能会出现这样的异常哦.
    //如果方法中没有出现异常,那么正常执行
    //如果方法中真的出现了异常,其实也是将这个异常交给了调用者处理.
    //如果声明的异常是一个运行时异常,那么声明的代码可以省略
    private static void method1() /*throws NullPointerException*/ {
        int [] arr = null;
        for (int i = 0; i < arr.length; i++) {//出现的空指针异常,还是由虚拟机创建出来的.
            System.out.println(arr[i]);
        }
    }

    //告诉调用者,你调用我,有可能会出现这样的异常哦.
    //如果方法中没有出现异常,那么正常执行
    //如果方法中真的出现了异常,其实也是将这个异常交给了调用者处理.
    //如果声明的异常是一个编译时异常,那么声明的代码必须要手动写出.
    private static void method2() throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        sdf.parse("2048-10月10日");
    }
}

注意事项

  • 这个throws格式是跟在方法的括号后面的

  • 编译时异常必须要进行处理,两种处理方案:try...catch …或者 throws,如果采用 throws 这种方案,在方法上进行显示声明,将来谁调用这个方法谁处理

  • 运行时异常因为在运行时才会发生,所以在方法后面可以不写,运行时出现异常默认交给jvm处理

3.6 throw抛出异常 (应用)

  • 格式

    throw new 异常();

  • 注意

    这个格式是在方法内的,表示当前代码手动抛出一个异常,下面的代码不用再执行了

  • throws和throw的区别

    throwsthrow
    用在方法声明后面,跟的是异常类名 用在方法体内,跟的是异常对象名
    表示声明异常,调用该方法有可能会出现这样的异常 表示手动抛出异常对象,由方法体内的语句处理
  • 示例代码

    • package com.itheima.exce;
      
      public class ExceptionDemo7 {
          public static void main(String[] args) {
              System.out.println("家里有一个貌美如花的老婆");
              System.out.println("还有一个当官的兄弟");
              System.out.println("自己还有一个买卖");
              System.out.println("这样的生活你要不要?");
              throw new RuntimeException(); //当代码执行到这里,就创建一个异常对象
              //该异常创建之后,暂时没有手动处理.抛给了调用者处理
              //下面的代码不会再执行了.
              //System.out.println("武大郎的标准生活");
          }
      }
        

抛出处理异常的意义

1.在方法中,当传递的参数有误,没有继续运行下去的意义了,则采取抛出措施,表示让该方法结束运行。

2.告诉调用者方法中出现了问题

package com.itheima.exce;

public class ExceptionDemo8 {
    public static void main(String[] args) {
        //int []arr={1,2,3,4,5};
        int []arr=null;
        printArr(arr);//就会接收到一个异常。
                    //我们还需要自己处理一下异常
    }

    private static void printArr(int[] arr) {
        if (arr == null) {
            //System.out.println("参数不能为null");
            throw new NullPointerException();//当参数位null的时候
                                            //手动创建了一个异常对象,抛给了调用者
        }else{
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i]);
            }
        }

    }
}

3.7 try-catch方式处理异常(应用)

  • 定义格式

    try {
    可能出现异常的代码;
    } catch(异常类名 变量名) {
    异常的处理代码;
    }
  • 执行流程

    • 程序从 try 里面的代码开始执行

    • 出现异常,就会跳转到对应的 catch 里面去执行

    • 执行完毕之后,程序还可以继续往下执行

  • 示例代码

package com.itheima.exce;

public class ExceptionDemo8 {
    public static void main(String[] args) {
        //好处:为了能让代码继续往下运行
        int []arr=null;
        try{
            //有可能发生异常的代码
            printArr(arr);
        }catch (NullPointerException e){
            //如果出现了这样的异常,那么我们进行的操作
            System.out.println("参数不能为null");
        }
        System.out.println("hahah ");
    }

    private static void printArr(int[] arr) {
        if (arr == null) {
            //System.out.println("参数不能为null");
            throw new NullPointerException();//当参数位null的时候
                                            //手动创建了一个异常对象,抛给了调用者
        }else{
            for (int i = 0; i < arr.length; i++) {
                System.out.println(arr[i]);
            }
        }

    }
}

注意

  1. 如果 try 中没有遇到问题,怎么执行?

    会把try中所有的代码全部执行完毕,不会执行catch里面的代码

  2. 如果 try 中遇到了问题,那么 try 下面的代码还会执行吗?

    那么直接跳转到对应的catch语句中,try下面的代码就不会再执行了当catch里面的语句全部执行完毕,表示整个体系全部执行完全,继续执行下面的代码

  3. 如果出现的问题没有被捕获,那么程序如何运行?

    那么try...catch就相当于没有写.那么也就是自己没有处理. 默认交给虚拟机处理.

  4. 同时有可能出现多个异常怎么处理?

    出现多个异常,那么就写多个catch就可以了. 注意点:如果多个异常之间存在子父类关系.那么父类一定要写在下面

package com.itheima.exce;

import java.util.Scanner;

public class ExceptionDemo10 {
    public static void main(String[] args) {
        //1.如果 try 中没有遇到问题,怎么执行? --- 会把try中所有的代码全部执行完毕,不会执行catch里面的代码
        //2.如果 try 中遇到了问题,那么 try 下面的代码还会执行吗?
        //那么直接跳转到对应的catch语句中,try下面的代码就不会再执行了
        //当catch里面的语句全部执行完毕,表示整个体系全部执行完全,继续执行下面的代码
        //3.如果出现的问题没有被捕获,那么程序如何运行?
        //那么try...catch就相当于没有写.那么也就是自己没有处理.
        //默认交给虚拟机处理.
        //4.同时有可能出现多个异常怎么处理?
        //出现多个异常,那么就写多个catch就可以了.
        //注意点:如果多个异常之间存在子父类关系.那么父类一定要写在下面

        // method1();
        try {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入你的年龄");
            String line = sc.nextLine();
            int age = Integer.parseInt(line);//格式化异常
            System.out.println(age);
            System.out.println(2 / 0); //数学异常
        } catch (Exception e) {
            System.out.println("看看我执行了吗");
            //以后我们针对于每种不同的异常,有可能会有不同的处理结果.
        }
        System.out.println("测试456");
    }

    private static void method1() {
        try {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入你的年龄");
            String line = sc.nextLine();
            int age = Integer.parseInt(line);//格式化异常
            System.out.println(age);
            System.out.println(2 / 0); //数学异常
        } catch (NumberFormatException e) {
            System.out.println("格式化异常出现了");
        }catch (ArithmeticException e) {
            System.out.println("数学运算异常出现了");
        }
        System.out.println("测试456");
    }
}

  

3.8 Throwable成员方法(应用)

  • 常用方法

    方法名说明
    public String getMessage() 返回此 throwable 的详细消息字符串
    public String toString() 返回此可抛出的简短描述
    public void printStackTrace() 把异常的错误信息输出在控制台
  • 示例代码

package com.itheima.exce;


public class ExceptionDemo11 {
    //public String getMessage()    返回此 throwable 的详细消息字符串
    //public String toString()      返回此可抛出的简短描述
    //public void printStackTrace() 把异常的错误信息输出在控制台(字体为红色的)
    public static void main(String[] args) {

        try {
            int [] arr = {1,2,3,4,5};
            System.out.println(arr[10]);//虚拟机帮我们创建了一个异常对象 new ArrayIndexOutOfBoundsException();
        } catch (ArrayIndexOutOfBoundsException e) {
            /*String message = e.getMessage();
            System.out.println(message);*/
           /* String s = e.toString();
            System.out.println(s);*/
            e.printStackTrace();
        }

        System.out.println("嘿嘿嘿");

    }
}

  两种处理异常方式的小结

抛出 throw throws

1.在方法中,当传递的参数有误,没有继续运行下去的意义了,则采用抛出处理,表示让该方法结束运行

2.告诉调用者出现了问题

捕获 try...catch

捕获:让代码继续往下运行

3.9 异常的练习 (应用)

  • 需求

    键盘录入学生的姓名和年龄,其中年龄为18 - 25岁,超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止

  • 实现步骤

    1. 创建学生对象

    2. 键盘录入姓名和年龄,并赋值给学生对象

    3. 如果是非法数据就再次录入

  • 代码实现

    学生类

 

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age >= 18 && age <= 25){
            this.age = age;
        }else{
            //当年龄不合法时,产生一个异常
            throw new RuntimeException("年龄超出了范围");
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类  

public class ExceptionDemo12 {
    public static void main(String[] args) {
        // 键盘录入学生的姓名和年龄,其中年龄为 18 - 25岁,
        // 超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止。

        Student s = new Student();

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入姓名");
        String name = sc.nextLine();
        s.setName(name);
       while(true){
           System.out.println("请输入年龄");
           String ageStr = sc.nextLine();
           try {
               int age = Integer.parseInt(ageStr);
               s.setAge(age);
               break;
           } catch (NumberFormatException e) {
               System.out.println("请输入一个整数");
               continue;
           } catch (AgeOutOfBoundsException e) {
               System.out.println(e.toString());
               System.out.println("请输入一个符合范围的年龄");
               continue;
           }
           /*if(age >= 18 && age <=25){
               s.setAge(age);
               break;
           }else{
               System.out.println("请输入符合要求的年龄");
               continue;
           }*/
       }
        System.out.println(s);

    }
}

3.10 自定义异常(应用)

  • 自定义异常概述

    当Java中提供的异常不能满足我们的需求时,我们可以自定义异常

  • 实现步骤

    1. 定义异常类     类名见名知意

    2. 写继承关系  要么继承RuntimeException   要么继承Exception

    3. 提供空参构造

    4. 提供带参构造

  • 代码实现

    异常类

public class AgeOutOfBoundsException extends RuntimeException {
    public AgeOutOfBoundsException() {
    }

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

学生类  

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age >= 18 && age <= 25){
            this.age = age;
        }else{
            //如果Java中提供的异常不能满足我们的需求,我们可以使用自定义的异常
            throw new AgeOutOfBoundsException("年龄超出了范围");
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类  

public class ExceptionDemo12 {
    public static void main(String[] args) {
        // 键盘录入学生的姓名和年龄,其中年龄为 18 - 25岁,
        // 超出这个范围是异常数据不能赋值.需要重新录入,一直录到正确为止。

        Student s = new Student();

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入姓名");
        String name = sc.nextLine();
        s.setName(name);
       while(true){
           System.out.println("请输入年龄");
           String ageStr = sc.nextLine();
           try {
               int age = Integer.parseInt(ageStr);
               s.setAge(age);
               break;
           } catch (NumberFormatException e) {
               System.out.println("请输入一个整数");
               continue;
           } catch (AgeOutOfBoundsException e) {
               System.out.println(e.toString());
               System.out.println("请输入一个符合范围的年龄");
               continue;
           }
           /*if(age >= 18 && age <=25){
               s.setAge(age);
               break;
           }else{
               System.out.println("请输入符合要求的年龄");
               continue;
           }*/
       }
        System.out.println(s);

    }
}

  

  

  

  

  

 

 

posted @ 2020-11-06 16:34  星梦泪痕  阅读(81)  评论(0编辑  收藏  举报