Java异常

1、什么是异常

  1. 概念:程序在运行过程中出现的不正常现象。出现异常不处理将终止程序运行。
  2. 异常处理的必要性:任何程序都可能存在大量的未知问题、错误。如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
  3. 异常处理:Java 编程语言使用异常处理机制为程序提供了异常处理的能力。

2、异常的分类

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

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

    • StackOverflowError
    • OutOfMemoryError
  • Exception:程序在运行和配置中产生的问题,可处理

    • RuntimeException:运行时异常,可处理,也可不处理。
    • CheckedException:检查时异常,必须处理。

2.1、常见运行时异常

package com.liuxiang;

/**
 * 演示常见运行时异常RuntimeException
 * @author 86187
 */
public class Demo01 {
    public static void main(String[] args) {
        //1. NullPointerException
        String name = null;
        System.out.println(name.equals("zhangshan"));
        //2. ArrayIndexOutOfBoundsException
        int[] arr = {1,2,3};
        System.out.println(arr[3]);
        //3. ClassCastException
        Object str1 = "123";
        Integer integer = (Integer) str1;
        //4. NumberFormatException
        String str2 = "123a";
        int i = Integer.parseInt(str2);
        //5. ArithmeticException
        int n = 10/0;
        System.out.println(n);
    }
}
Exception in thread "main" java.lang.NullPointerException
	at com.liuxiang.Demo01.main(Demo01.java:12)

3、异常的产生和传递

异常的产生:当程序在运行时遇到不符合规范的代码或结果时,会产生异常或程序员使用 throw 关键字手动抛出异常。
异常的传递:按照方法的调用链反向传递,如始终没有处理异常,最终会由 JVM 进行默认异常处理(打印堆栈跟踪信息)并中断程序运行。

package com.liuxiang;

import java.util.Scanner;

/**
 * 演示异常的产生和传递
 * 要求:输入两个数字实现两个数字相除
 * @author 86187
 */
public class Demo02 {
    public static void main(String[] args) {
        operation();
    }

    public static void operation(){
        divide();
    }

    public static void divide(){
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入第一个数字");
        int num1 = scanner.nextInt(); //如果出现异常没有处理,程序中断
        System.out.println("请输入第二个数字");
        int num2 = scanner.nextInt();
        int result = num1/num2; //如果出现异常没有处理,所以程序中断
        System.out.println(result);
        System.out.println("程序执行完毕了...");
    }

}
请输入第一个数字
a
Exception in thread "main" java.util.InputMismatchException
	at java.util.Scanner.throwFor(Scanner.java:864)
	at java.util.Scanner.next(Scanner.java:1485)
	at java.util.Scanner.nextInt(Scanner.java:2117)
	at java.util.Scanner.nextInt(Scanner.java:2076)
	at com.liuxiang.Demo02.divide(Demo02.java:22)
	at com.liuxiang.Demo02.operation(Demo02.java:16)
	at com.liuxiang.Demo02.main(Demo02.java:12)

4、异常处理

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

  • try:执行可能产生异常的代码
  • catch:捕获异常,并处理
  • finally:无论是否发生异常,代码总能执行
  • throw:手动抛出异常
  • throws:声明方法可能要抛出的各种异常

4.1、try...catch...

package com.liuxiang;

import java.util.Scanner;

/**
 * 演示try...catch...语句使用
 * (1)正常没有发生异常
 * (2)发生异常并捕获
 * (3)异常类型不匹配
 * @author 86187
 */
public class Demo03 {
    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; //ArithmeticException
        } catch (Exception e) { //捕获Exception:是所有异常的父类
            e.printStackTrace(); //打印堆栈跟踪信息
            System.out.println(e.getMessage());
        }
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}
请输入第一个数字
1
请输入第二个数字
0
java.lang.ArithmeticException: / by zero
	at com.liuxiang.Demo03.main(Demo03.java:21)
/ by zero
结果是:0
程序结束了...

4.2、try...catch...finally

package com.liuxiang;

import java.util.Scanner;

/**
 * 演示try...catch...finally...语句使用
 * finally做后的:表示有没有异常都会执行的代码
 * (1)正常没有发生异常
 * (2)发生异常并捕获
 * (3)异常类型不匹配
 * @author 86187
 */
public class Demo04 {
    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; //ArithmeticException

            //System.exit(0); //手动退出JVM则不会执行finally
        } catch (Exception e) { //捕获Exception:是所有异常的父类
            e.printStackTrace(); //打印堆栈跟踪信息
            System.out.println(e.getMessage());
        }
        finally {
            System.out.println("释放资源");
        }
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}
请输入第一个数字
a
java.util.InputMismatchException
	at java.util.Scanner.throwFor(Scanner.java:864)
	at java.util.Scanner.next(Scanner.java:1485)
	at java.util.Scanner.nextInt(Scanner.java:2117)
	at java.util.Scanner.nextInt(Scanner.java:2076)
	at com.liuxiang.Demo04.main(Demo04.java:19)
null
释放资源
结果是:0
程序结束了...

4.3、多重catch

package com.liuxiang;

import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * 演示多重catch语句使用
 * (1)正常没有发生异常
 * (2)发生异常并捕获
 * (3)异常类型不匹配
 * @author 86187
 */
public class Demo05 {
    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; //ArithmeticException
        } catch (ArithmeticException e) {
            System.out.println("算术异常");
        }
        catch (InputMismatchException e){
            System.out.println("输入不匹配异常");
        }
        catch (Exception e){ //捕获Exception:是所有异常的父类
            System.out.println("未知异常");
        }
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}
请输入第一个数字
a
输入不匹配异常
结果是:0
程序结束了...
请输入第一个数字
10
请输入第二个数字
0
算术异常
结果是:0
程序结束了...

4.4、try...finally

package com.liuxiang;

import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * 演示多重try...finally...语句使用
 * 不能处理异常,可以释放资源,把异常向上抛出
 * @author 86187
 */
public class Demo06 {
    public static void main(String[] args) {
        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; //ArithmeticException
        }finally {
            System.out.println("释放资源");
        }
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}
请输入第一个数字
10
请输入第二个数字
0
释放资源
出现异常:/ by zero

5、声明异常

  • 如果在一个方法体中抛出了异常,如何通知调用者?
  • throws 关键字:声明异常
  • 使用原则:底层代码向上声明或者抛出异常,最上层一定要处理异常,否则程序中断。
package com.liuxiang;

import java.util.Scanner;

/**
 * throws:声明异常
 * @author 86187
 */
public class Demo07 {
    public static void main(String[] args) {
        try {
            divide();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static void divide() throws Exception{
        Scanner input = new Scanner(System.in);
        System.out.println("请输入第一个数字");
        int num1 = input.nextInt(); //InputMismatchException
        System.out.println("请输入第二个数字");
        int num2 = input.nextInt();
        int result = num1/num2; //ArithmeticException
        System.out.println("结果是:"+result);
        System.out.println("程序结束了...");
    }
}
请输入第一个数字
10
请输入第二个数字
0
/ by zero

6、抛出异常

  • 除了系统自动抛出异常外,有些问题需要程序员自行抛出异常。
  • throw 关键字:抛出异常
  • 语法:throw 异常对象
package com.liuxiang;

public class Person {
    private String name;
    private String sex;
    private int age;

    public Person() {
    }

    public Person(String name, String sex, int age) {
        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) {
        if (sex.equals("男")||sex.equals("女")){
            this.sex = sex;
        }
        else {
            throw new RuntimeException("性别输入错误"); //运行时异常
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age>0&&age<=120){
            this.age = age;
        }
        else {
            //抛出异常
            throw new RuntimeException("年龄不符合要求");
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.liuxiang;

public class TestPerson {
    public static void main(String[] args) {
        Person person = new Person();
        person.setSex("1");
        person.setAge(200);
        System.out.println(person.toString());
    }
}
Exception in thread "main" java.lang.RuntimeException: 性别输入错误
	at com.liuxiang.Person.setSex(Person.java:34)
	at com.liuxiang.TestPerson.main(TestPerson.java:6)

7、自定义异常

  • 需继承自 Exception 或 Exception 的子类,常用 RuntimeException。
  • 必要提供的构造方法:
    • 无参数构造方法
    • String message 参数的构造方法
package com.liuxiang;

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

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

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

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

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

public class Person {
    private String name;
    private String sex;
    private int age;

    public Person() {
    }

    public Person(String name, String sex, int age) {
        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) {
        if (sex.equals("男")||sex.equals("女")){
            this.sex = sex;
        }
        else {
            throw new RuntimeException("性别输入错误"); //运行时异常
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age>0&&age<=120){
            this.age = age;
        }
        else {
            //抛出异常
            throw new AgeException("年龄不符合要求"); //自定义异常
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", age=" + age +
                '}';
    }
}
package com.liuxiang;

public class TestPerson {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(200);
        System.out.println(person.toString());
    }
}
Exception in thread "main" com.liuxiang.AgeException: 年龄不符合要求
	at com.liuxiang.Person.setAge(Person.java:48)
	at com.liuxiang.TestPerson.main(TestPerson.java:6)
posted @ 2021-08-13 16:34  有一个大佬梦  阅读(107)  评论(0)    收藏  举报