Loading

13、异常

1、什么是异常

概念:

  程序在运行过程中出现的不正常现象。出现异常不处理将终止程序运行。

异常处理的必要性:

  任何程序都可能存在大量的未知问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。

异常处理:

  Java编程语言使用异常处理机制为程序提供了异常处理的能力。

2、异常的分类

Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。

  l- Error: JVM、硬件、执行逻辑错误,不能手动处理。

    l- StackOverflowError 栈空间溢出

    l- OutOfMemoryError  内存不足

  l- Exception:程序在运行和配置中产生的问题,可处理。

    l- RuntimeException:运行时异常,可处理,可不处理。

    l- CheckedException:检查时异常,必须处理。

3、常见运行时异常

/**
 * 演示常见运行时异常
 * 运行时异常:RuntimeException以及子类
 * 检查时异常:Exception以及子类,除了RuntimeException
 *
 */
public class Demo1 {
    public static void main(String[] args) {
        //常见运行时异常

        //1NullPointerException
//        String name=null;
//        System.out.println(name.equals("zhangsan"));

        //2ArrayIndexOutOfBoundsException
//        int[] arr= {10,30,50};
//        System.out.println(arr[3]);

        //3ClassCastException
//        Object str="hello";
//        Integer i=(Integer)str;

        //4NumberFormatException
//        int n=Integer.parseInt("100a");
//        System.out.println(n);

        //5ArithmeticExceptioin
//        int n=10/0;
//        System.out.println(n);

//        检查时异常
//        try {
//            FileInputStream fis=new FileInputStream("d:\\hell.txt");
//        } catch (FileNotFoundException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
    }
}

4、异常的产生

自动抛出异常:

  当程序在运行时遇到不符合规范的代码或结果时,会产生异常。

手动抛出异常:

  语法: throw new异常类型(“实际参数”);

产生异常结果:

  相当于遇到return语句,导致程序因异常而终止。

5、异常的传递

异常的传递:

  按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。

受查异常:

  throws声明异常,修饰在方法参数列表后端。

运行时异常:

  因可处理可不处理,无需声明异常。

/**
 * 演示异常的产生和传递
 * 要求:输入两个数字实现两个数字相除
 *
 */
public class Demo2 {
    public static void main(String[] args) {
        operation();
    }
    public static void operation() {
        System.out.println("---opration-----");
        divide();
    }
    public static void divide() {
        Scanner input=new Scanner(System.in);
        System.out.println("请输入第一个数字");
        int num1=input.nextInt();//出现异常,没有处理,程序中断
        System.out.println("请输入第二个数字");
        int num2=input.nextInt();
        int result=num1/num2;//出现异常没有处理,所以程序中断
        System.out.println("结果:"+result);
        System.out.println("程序执行完毕了...");
    }
}

6、异常处理

Java的异常处理是通过5个关键字来实现的:

  try: 执行可能产生异常的代码

  catch: 捕获异常,并处理

  finally: 无论是否发生异常,代码总能执行

  throw: 手动抛出异常

  throws: 声明方法可能要抛出的各种异常

6.1、try...catch

会三种情况:

  1:正常请求

  2:出现异常并处理

  3:异常类型不匹配

        try {
            // 可能出现异常的代码
        }catch (Exception e){
            // 异常处理的相关代码,如:getMessage(). printStackTrace()
        }
/**
 * 演示try...catch...语句的使用
 * try{...可能发生异常的代码}
 * catch{...捕获异常,并处理异常}
 * 三种情况:
 * (1)正常没有发生异常
 * (2)发生异常并捕获
 * (3)发生异常,不能捕获
 *
 */
public class Demo3 {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int result=0;
        try {
            System.out.println("请输入第一个数字");
            int num1=input.nextInt();//InputMismatchException
            System.out.println("请输入第二个数字");
            int num2=input.nextInt();
            result=num1/num2;//发生异常// ArethmicException
        }catch (Exception e) {//捕获 Exception:是所有异常的父类
            //处理
            //e.printStackTrace();
            System.out.println(e.getMessage());
        }
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}

6.2、try...catch...finally

(1)finally块是否发生异常都执行,可以释放资源

(2)finally块不执行的唯一情况,退出java虚拟机

        try{
            // 可能出现异常的代码
        }catch (Exception e){
            // 异常处理的相关代码,如:getMessage(). printStackTrace()
        }finally {
            // 是否发生异常都会执行,可以释放资源等
        }
/**
 * 演示try...catch...finally...使用
 * finally最后的
 * 表示有没有发生异常都会执行的代码
 *
 */
public class Demo4 {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int result=0;
        try {
            System.out.println("请输入第一个数字");
            int num1=input.nextInt();//InputMismatchException
            System.out.println("请输入第二个数字");
            int num2=input.nextInt();
            result=num1/num2;//发生异常// ArethmicException
            //手动退出JVM
            //System.exit(0);
        }catch (Exception e) {//捕获 Exception:是所有异常的父类
            //处理
            //e.printStackTrace();
            System.out.println(e.getMessage());
        }finally {
            System.out.println("释放资源...");
        }
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}

6.3、多重catch

(1)子类异常在前,父类异常在后

(2)发生异常时按顺序逐个匹配

(3)只执行第一个与异常类型匹配的catch语句

(4) finally根据需要可写或不写

        try {
            // 可能出现异常的代码
        }catch (异常类型1){
            // 满足异常类型1执行的相关代码
        }catch (异常类型2){
            // 满足异常类型2执行的相关代码
        }catch (异常类型3){
            // 满足异常类型3执行的相关代码
        }
/**
 * 演示多重catch的使用
 * try...catch(类型1)...catch(类型2)...
 *
 */
public class Demo5 {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int result=0;
        try {
//            String string=null;
//            System.out.println(string.equals("hello"));
            System.out.println("请输入第一个数字");
            int num1=input.nextInt();//InputMismatchException
            System.out.println("请输入第二个数字");
            int num2=input.nextInt();
            result=num1/num2;//发生异常// ArethmicException
        }catch (ArithmeticException e) {//捕获 Exception:是所有异常的父类    
            System.out.println("算术异常");
        }catch (InputMismatchException e) {
            System.out.println("输入不匹配异常");
        }catch (Exception e) {
            System.out.println("未知异常");
        }
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}

6.4、try...finally

try...finally不能捕获异常,仅仅用来当发生异常时,用来释放资源。

一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。

        try {
            // 可能出现异常的代码
        }finally {
            // 是否发生异常都会执行,可以释放资源等...
        }
/**
 * try...finally的使用
 * 不能处理异常,可以释放资源,把异常向上抛出
 *
 */
public class Demo6 {
    public static void main(String[] args) {//JVM
        try {
            divide();
        }catch (Exception e) {
            System.out.println("出现异常:"+e.getMessage());
        }
    }
    public static void divide() {
        Scanner input=new Scanner(System.in);
        int result=0;
        try {
            System.out.println("请输入第一个数字");
            int num1=input.nextInt();//InputMismatchException
            System.out.println("请输入第二个数字");
            int num2=input.nextInt();
            result=num1/num2;//发生异常// ArethmicException
        }finally {
            System.out.println("释放资源");
        }
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}

7、声明异常

如果在一个方法体中抛出了异常,如何通知调用者?

throws关键字:声明异常

使用原则:

  底层代码向上声明或者抛出异常,最上层一定要处理异常,否则程序中断。

/**
 * throws:声明异常
 *
 */
public class Demo7 {
    public static void main(String[] args){//JVM
        try {
            divide();
        } catch (Exception e) {
            //e.printStackTrace();
            System.out.println(e.getMessage());
        }
        
    }
    public static void divide() throws Exception {
        Scanner input=new Scanner(System.in);
        System.out.println("请输入第一个数字");
        int num1=input.nextInt();
        System.out.println("请输入第二个数字");
        int num2=input.nextInt();
        int result=num1/num2;
        System.out.println("结果:"+result);
    }
}

8、抛出异常

除了系统自动抛出异常外,有些问题需要程序员自行抛出异常。

throw关键字: 抛出异常

语法: throw 异常对象;

public class Person {
    private String name;
    private String sex;
    private int age;
    public Person() {
    }
    public Person(String name, String sex, int age) {
        super();
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) throws Exception {
        if(sex.equals("男")||sex.equals("女")) {
            this.sex = sex;
        }else {
            throw new Exception("性别不符合要求");
        }
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) throws Exception {
        if(age>0&&age<=120) {
            this.age = age;
        }else {
            //抛出异常
            throw new Exception("年龄不符合要求");
        }
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
    }
    
}
public class TestPerson {
    public static void main(String[] args) throws Exception{
        Person xiaozhang=new Person();
        xiaozhang.setAge(20);
        xiaozhang.setSex("妖");
        System.out.println(xiaozhang.toString());
    }
}

9、自定义异常

需继承自Exception或Exception的子类,常用RuntimeException.

必要提供的构造方法:

  无参数构造方法

  String message参数的构造方法

/**
 * 自定义异常
 * (1)继承Exception 或子类
 * (2)添加构造方法
 *
 */
public class AgeException extends RuntimeException{

    public AgeException() {
        super();
    }

    public AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

    public AgeException(String message, Throwable cause) {
        super(message, cause);
    }

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

    public AgeException(Throwable cause) {
        super(cause);
    }
}

10、方法覆盖(重写)

带有异常声明的方法覆盖:

  方法名、参数列表、返回值类型必须和父类相同。

  子类的访问修饰符合父类相同或是比父类更宽。

  子类中的方法,不能抛出比父类更多、更宽的检查时异常。

public class Animal {
    public void eat() throws Exception{
        System.out.println("父类吃方法..........");
    }
}
public class Dog extends Animal{
    @Override
    public void eat() throws Exception{
        System.out.println("子类的吃的方法..........");
    }
}

11、总结

异常的概念:

  程序在运行过程中出现的特殊情况。

异常的分类:

  RuntimeException: 运行时异常,可处理,可不处理。

  CheckedException: 检查时异常,必须处理。

异常的产生:

  程序遇到错误,或手动抛出异常

异常的传递:

  按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)

异常的处理:

  try { } catch { } finally { }

带有异常声明的方法覆盖:

  子类中的方法,不能抛出比父类更多、更宽的异常。

posted @ 2021-09-05 21:07  菜鸟的道路  阅读(114)  评论(0)    收藏  举报