JavaLearn # 异常

Posted LRcoding

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaLearn # 异常相关的知识,希望对你有一定的参考价值。

1. 异常

异常,总会发生的情况,异常处理完,代码要继续执行

例如:除数为 0 ,或者不为数字。

面对异常该怎么办呢?

  • 由开发者通过 if-else 来解决 ==》 代码臃肿,对程序员要求较高
  • Java本身的异常处理机制,我们只需要捕捉,处理异常即可,处理完程序继续执行

异常处理过程

  • 捕获异常:
    • try:内含可能产生异常的代码
    • catch:捕获异常
    • finally无论是否发生异常,程序都需要执行的代码
  • 声明异常(有异常,自己不处理):
    • throws:声明方法可能要抛出的各种异常
  • 抛出异常(异常产生的地方):
    • throw:手动抛出异常

示例:输入班级总分,输入人数,计算平均分

public class TestException {
    public static void main(String[] args) {
        // 1. 输入总分
        Scanner sc = new Scanner(System.in);
        System.out.print("输入总分: ");
        int score = sc.nextInt();  // 可能输入的不是 int 类型,报异常

        // 2. 输入人数
        System.out.print("输入班级人数: ");
        int num = sc.nextInt();

        // 3. 计算平均分并输出
        int res = score / num;     // 此处除法,容易出现异常
        System.out.println("平均分:" + res);

        System.out.println("ending.....");
    }
}

解决:try-catch-finally 处理异常; throws 抛出异常不处理,调用者处理

// 将可能出现异常的语句,放到 try 语句里,catch 处理异常,finally 总会执行的代码
try {
    int score = sc.nextInt();
    int num = sc.nextInt();
    int res = score / num;
} catch (Exception e) {
    System.out.println("异常出现了");
} finally {
    System.out.println("总会执行的代码");
}

// 处理完异常后,后续的代码可以继续执行
System.out.println("可以继续执行 ");

try-catch执行情况

  • 情况1:try 代码块中没有异常 ==》 不执行 catch 代码块,执行后续代码
  • 情况2:try 代码块中出现异常,catch 中异常类型匹配(相同或者父类) ==》 执行 catch 代码块,执行后续代码
  • 情况3:try 代码块中出现异常,catch 中异常类型不匹配 ==》 不执行 catch 代码块,不执行后续代码

注意

  • 出现异常后,Java会产生相应的异常对象,Java系统寻找匹配的 catch 块,找到后将异常对象赋给catch块异常参数
  • 出现异常后,try 块中尚未执行的代码语句,不会执行
  • 出现异常并处理后,catch 块后面的语句还会执行

catch 块中如何处理异常

  • 输出用户自定义的异常信息System.err.println("除数不能为 0");
  • 调用异常对象的方法输出异常信息: e.printStackTrace(); 异常的堆栈信息
  • 继续向上抛出异常: throw e catch 后续的代码块不执行

加上 finally 后的执行顺序

  • 无论 try 中是否发生异常,finally 中的代码都要被执行,所以如果在 try 语句中有 return 方法,那么顺序为正常执行 return 之前的,然后执行 finally 中代码,然后执行 return
  • 但是如果使用了 System.exit(0); 那么程序只执行到这个语句处

多重 catch 处理异常:只匹配一个异常

try{
    int score = sc.nextInt();
    int res = score / num; // 此处除法,容易出现异常
} catch (ArithmeticException e) {
    System.err.println("除数不能为 0");
} catch (InputMismatchException e) {
    System.err.println("必须输入数字");
} catch (Exception e) {
    e.printStackTrace();
}

2. 异常体系

Error

  • Java 运行时系统内部错误或资源耗尽错误,一般指与 JVM 或动态加载等相关的问题
  • 这类错误是我们无法控制的,同时也非常罕见,不需要去管理 Error

Exception

  • 所有异常的父类,其子类对应了各种各样可能出现的异常

Exception分类

  • Runtime Exception 运行时异常

    可不必对其处理,系统自动检测处理,其产生比较繁琐,处理麻烦(被0整除,数组越界,空指针等)

  • Checked Exception 检查异常

    必须捕获处理,否则会编译错误,只有Java提供了检查异常

    Class.forName("java.lang.String").newInstance();
    
    两种处理方式:
    // 1. 用 try-catch 包围
    // 2. 用 throws 继续向上抛,让调用者进行异常处理
    

3. throw 和 throws

  • 作用:
    • throws 是声明一下,方法里面有异常,调用者要进行处理
    • throw 声明的是产生异常的地方,要往上抛,让调用者知道
  • 位置:
    • throws 写在方法的签名位置(声明的地方)
    • throw 写在方法体内部
  • 数量:
    • throws 后面可以加多个
    • throw 后面只能由一个对象

需求1:如果班级人数输入的为负数,抛出异常

  1. 抛出运行时异常 throw new RuntimeException

    System.out.print("输入班级人数: ");
    int num = sc.nextInt();
    
    if (num < 0) {
        // =========== throw 是产生异常的地方,进行抛出 ================
        throw new RuntimeException("人数不能是负数");
    }
    
  2. 抛出检查异常 throw new Exception

    // =========== throws 抛出异常,告知调用者,要进行异常处理 ================
    public void getAvg() throws Exception {
        System.out.print("输入班级人数: ");
        int num = sc.nextInt();
        if (num < 0) {
            throw new Exception("人数不能是负数");
        }
    }
    

需求2:限制一下年龄的范围

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

    public Person() {
    }

    public Person(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) throws Exception{
        if (age < 0 || age > 130) {
            // 第1种:抛出运行时异常,可以不进行处理
            //throw new RuntimeException("年龄范围错误(0-130)");

            // 第2种:抛出检查异常,调用的地方必须处理,声明方法时,必须加上 throws
            throw new Exception("年龄范围错误(0-130)");
        }
        this.age = age;
    }

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

    public static void main(String[] args) {
        Person p = new Person();
        p.setName("张三");
        try {
            p.setAge(150);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(p.toString());
    }
}

4. 自定义异常

上边代码运行后,会产生异常,但是不友好,不能见名知意

解决:我们可以自定义异常类型,抛出时,抛出我们自定义的异常

自定义异常类AgeException

// 检查异常:继承 Exception,  运行时异常:继承 RuntimeException
public class AgeException extends Exception {  
    public AgeException () {
    }

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

使用自定义异常

public class Person {
    private int age;

    public void setAge(int age) throws AgeException {   //============== 抛出自定义异常类 ===========
        if (age < 0 || age > 130) {
            throw new AgeException("年龄范围错误(0-130)");
        }
        this.age = age;
    }

    public static void main(String[] args) {
        Person p = new Person();
        try {
            p.setAge(150);
        } catch (AgeException e) {   //============== 使用自定义异常类进行捕获 ===========
            e.printStackTrace();
        }
        System.out.println(p.toString());
    }
}

扩展:异常链,项目分层之后,底层出现问题,向上抛出,到合适的位置进行捕获处理

以上是关于JavaLearn # 异常的主要内容,如果未能解决你的问题,请参考以下文章

异常和TCP通讯

片段中的Android致命异常

JavaLearn# (13)多线程:线程生命周期线程控制线程同步线程通信线程池ForkJoin框架

mvn命令异常:An error has occurred in Javadoc report generation: Unable to find javadoc command异常已解决(代码片段

mvn命令异常:An error has occurred in Javadoc report generation: Unable to find javadoc command异常已解决(代码片段

springcloud报错-------关于 hystrix 的异常 FallbackDefinitionException:fallback method wasn't found(代码片段