从零学Java 异常

发布时间:2024年01月10日

Java 异常

1 异常的概念

概念:程序在运行过程中出现的特殊(不正常)情况。

异常处理的必要性:任何程序都可能存在大量的未知问题、错误;

如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。

2 异常的分类

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

2.1 错误

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

  • StackOverFlowError: 栈空间溢出错误
  • OutOfMemoryError: 堆空间溢出错误

2.2 异常

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

  • RuntimeException:运行时异常,可处理,可不处理。
  • 【CheckedException】:检查(编译)时异常,必须处理,除了RuntimeException其它都是检查(编译)时异常。

2.3 常见运行时异常

类型说明
NullPointerException空指针异常
ArrayIndexOutOfBoundsException数组越界异常
ClassCastException类型转换异常
NumberFormatException数字格式化异常
ArithmeticException算术异常

3 异常的产生

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

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

4 异常的传递

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

eg:

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 StageOne.day16.Exception.Test.main(Test.java:17)

5 异常处理关键字

关键字说明
try可能出现异常的代码
catch捕获异常
finally异常最终处理,释放资源
throw抛出异常
throws声明异常

6 常见异常处理结构

6.1 try{ } catch{ } 结构

三种情况:

  • 正常执行
  • 出现异常并处理
  • 异常类型不匹配

语法:

try {
//可能出现异常的代码
} catch(Exception e) {
//异常处理的相关代码,如:getMessage()、printStackTrace() 
}

eg:

public class Test {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int r = 0;
        try {
            System.out.println("请输入第一个数: ");
            int i = input.nextInt();
            System.out.println("请输入第二个数: ");
            int i1 = input.nextInt();
            r = i/i1;
        } catch (Exception e) {
            e.printStackTrace();   
        }
        System.out.println("结果是: "+r);
    }
}

6.2 try{ } catch{ } finally{ } 结构

语法:

try {
//可能出现异常的代码
} catch(Exception e) {
//异常处理的相关代码,如:getMessage()、printStackTrace() 
}finally{
//是否发生异常都会执行,可以释放资源等...
}

注:

  • finally块是否发生异常都执行,可以资源释放等。
  • finally块不执行的唯一情况,提前退出Java虚拟机

eg:

public class Test {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int r = 0;
        try {
            System.out.println("请输入第一个数: ");
            int i = input.nextInt();
            System.out.println("请输入第二个数: ");
            int i1 = input.nextInt();
            r = i/i1;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("最总处理, 释放资源");
        }
        System.out.println("结果是:"+r);
    }
}

6.3 try{ } catch{ } catch{ }…结构

语法:

try{
//可能出现异常的代码
}catch(异常类型1){
//满足异常类型1执行的相关代码
}catch(异常类型2){
//满足异常类型2执行的相关代码
}catch(异常类型3){
//满足异常类型3执行的相关代码
}

注:

  • 子类异常在前,父类异常在后
  • 发生异常时按顺序逐个匹配,只执行第一个与异常类型匹配的catch语句

eg:

public class Test {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int r = 0;
        try {
            System.out.println("请输入第一个数: ");
            int i = input.nextInt();
            System.out.println("请输入第二个数: ");
            int i1 = input.nextInt();
            r = i/i1;
        } catch (ArithmeticException e) {
            System.out.println("算术异常");
        } catch (InputMismatchException e) {
            System.out.println("输入不匹配异常");
        } catch (Exception e) {
            System.out.println("未知异常");
        }
        System.out.println("结果是: "+r);
    }
}

6.4 try{ } catch{ } catch{ } finally{ }结构

语法:

try{
//可能出现异常的代码
}catch(异常类型1){
//满足异常类型1执行的相关代码
}catch(异常类型2){
//满足异常类型2执行的相关代码
}finally{
//是否发生异常都会执行,可以释放资源等...
}

eg:

public class Test {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int r = 0;
        try {
            System.out.println("请输入第一个数: ");
            int i = input.nextInt();
            System.out.println("请输入第二个数: ");
            int i1 = input.nextInt();
            r = i/i1;
        } catch (ArithmeticException | InputMismatchException e) {
            System.out.println("算术异常或输入不匹配异常");
        } catch (Exception e) {
            System.out.println("未知异常");
        } finally {
            System.out.println("最终处理,释放资源");
        }
        System.out.println("结果是: "+r);
    }
}

6.5 try{ } finally{ } 结构

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

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

语法:

try{
//可能出现异常的代码
}finally{
//是否发生异常都会执行,可以释放资源等...
}

eg:

public class Test01 {
    public static void main(String[] args) {
        try {
            divide();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("程序结束了...");
    }

    public static void divide() {
        Scanner input = new Scanner(System.in);
        int r = 0;
        try {
            System.out.println("请输入第一个数: ");
            int i = input.nextInt();
            System.out.println("请输入第二个数: ");
            int i1 = input.nextInt();
            r = i/i1;
        } finally {
            System.out.println("最终处理,释放资源");
        }
        System.out.println("结果是: "+r);
    }
}

6.6 面试题

  1. try{}、catch{}、finally{}中是否可以包含return语句?

? 答: 语法上都可以, 但不推荐在finally中写, 否者会输出错误的数据

  1. 如果try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会执行?

? 答: 会执行

  1. 以下代码返回多少?并说明执行过程。

    eg:

    public class Test02 {
        public static void main(String[] args) {
            System.out.println(getNum());
        }
    
        public static int getNum() {
            int num = 10;
            try {
                return num++;
            } catch (Exception e) {
                return num++;
            } finally {
                num++;
            }
        }
    }
    
    res: 10
        
    public class Test02 {
        public static void main(String[] args) {
            System.out.println(getNum());
        }
    
        public static int getNum() {
            int num = 10;
            try {
                return num++;
            } catch (Exception e) {
                return num++;
            } finally {
                return num++;
            }
        }
    }
    
    res: 11
    

7 throws - 声明异常

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

throws关键字:声明异常,通知调用者此方法有异常。

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

注意事项

  • (1)如果方法抛出的是检查时异常,调用者必须处理,如果是运行时异常,可以不处理(不建议, 都要处理)。
  • (2)可以声明抛出多个异常类型,中间用逗号隔开。

eg:

public class Test01 {
    public static void main(String[] args) {
        try {
            divide();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("程序结束了...");
    }

    //throws:声明异常,告诉调用者有异常
    public static void divide() throws Exception {
        Scanner input = new Scanner(System.in);
        int r = 0;
        System.out.println("请输入第一个数: ");
        int i = input.nextInt();
        System.out.println("请输入第二个数: ");
        int i1 = input.nextInt();
        r = i / i1;
        System.out.println("结果是"+r);
    }
}

8 throw - 抛出异常

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

throw关键字:抛出异常

语法: throw 异常对象;

eg:

在setAge(int age)中对年龄进行判断,如果年龄介于1到100直接赋值,否则抛出异常。
在setGender(String gender)中对性别进行判断,如果性别是男或女直接赋值,否则抛出异常
在测试类中创建对象并调用setAge(int age)方法,使用try...catch捕获并处理异常。

Student:

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

    public Student(int age, String gender) throws Exception {
        this.setAge(age);
        this.setGender(gender);
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) throws Exception{
        if (age<1 || age>100) {
            throw new Exception("异常年龄输入");
        } else {
            this.age = age;
        }

    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) throws Exception {
        if (gender.equals("男")||gender.equals("女")) {
            this.gender = gender;
        } else {
            throw new Exception("异常性别输入");
        }
    }

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

TestStudent:

public class TestStudent {
    public static void main(String[] args) {
        Student stu = null;
        try {
            stu = new Student(120, "男");
        } catch (Exception e) {
            System.out.println("数据异常, 请重新输入...");
        }
        System.out.println(stu);
    }
}

9 自定义异常

概念:需继承Exception或Exception的子类,代表特定问题。

经验:异常类型名称望文生义,可在发生特定问题时抛出对应的异常。

eg:

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

    public AgeException(String message) {
        super(message);
    }
}
public class GenderException extends RuntimeException{
    public GenderException() {
    }

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

10 带有异常声明的方法重写

规则:

  • 子类继承父类,方法名、参数列表、返回值类型必须和父类相同。
  • 子类的访问修饰符和父类相同或是比父类更宽。
  • 子类中的方法,不能抛出比父类更多、更宽的检查时异常。
文章来源:https://blog.csdn.net/weixin_50858647/article/details/135497131
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。