12、异常Exception:

12、异常Exception:

我们来看一段代码,了解下为什么需要异常处理:

package com.jiangxian.Exception_;

/**
 * @author JiangXian~
 * @version 1.0
 */
public class Exception01 {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 0;
        int res = num1/num2;
        System.out.println("程序继续运行...");
    }
}

好的,这段代码会报错,出错的原因是除数为0了。我们来想一想这样子合不合理,倘若我们有一个很庞大的代码,我们因为这一个非常细微的错误,导致我们代码的崩溃,从而后续的所有代码都不执行了,这样做合理吗?显然是不合理的,这样我们的系统不够健壮

解决方法:异常捕获

对异常进行捕获,保证程序可以继续运行。

package com.jiangxian.Exception_;

/**
 * @author JiangXian~
 * @version 1.0
 */
public class Exception01 {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 0;

        // 1.num1/num2 => 10/0
        // 2.当执行到 num1/num2 因为 num2 = 0,程序就会出现(抛出)异常,此处为 ArithmeticException
        // 3.当抛出异常后,程序就崩溃了,下面的代码就不再执行;
        // 4.当我们认为一段代码可能出现 异常/问题,可以使用 try-catch
        try {
            int res = num1/num2;
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("程序继续运行...");
        // 加入异常处理机制,虽然有异常仍然会执行后面的代码。
    }
}


异常介绍:

基本概念:

java语言中,将程序执行中发生的不正常情况称为“异常“。(开发过程中的语法错误和逻辑错误不是异常!)

可以分为两大类:

  1. Error(错误):java虚拟机无法解决的严重问题。如JVM系统内部错误,资源耗尽等严重情况。
  2. Exception:因编译错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。其还能继续细分。
    1. 运行时异常(RUNTIME),在程序运行时会发生的异常;
    2. 编译时异常,编译器检查出的异常。

异常体系图:

  1. 异常分为两大类,运行时异常和编译时异常;
  2. 运行时异常,编译器检查不出来。一般指编程时的逻辑错误,==程序员应该尽力去避免其出现(否则整个代码中全是try-catch语句)。对于运行时异常,可以不做异常处理,报错了去更改即可,否则这种异常过于普遍,导致程序的可读性大大降低;
  3. 编译时异常,是编译器要求必须处理的异常。

常见的运行时异常:

  1. NullPointException——空指针异常;
  2. ArithmeticException——数学运算异常;
  3. ArrayIndexOutOfBoundsException——数组下标越界异常;
  4. ClassCastException——类型转换异常;
  5. NumberFormatException——数字格式不正确异常。

举例:

NullPointException:

当应用程序在需要对象的地方使用null时,抛出异常。(对象还没有创建出来就使用了)

package com.jiangxian.Exception_;

/**
 * @author JiangXian~
 * @version 1.0
 */
public class NullPointException_ {
    public static void main(String[] args) {
        String name = null;
        System.out.println(name.length());
    }
}

ArithmeticException:

当出现异常的运算条件时,抛出此异常。例如一个整数除以0。

/**
 * @author JiangXian~
 * @version 1.0
 */
public class ArithmeticException_ {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 0;
        int res = num1 / num2;
    }
}

ArrayIndexOutOfBoundsException:

用非法的索引去访问数组时抛出的异常。如索引为负数或大于等于数组的length-1,则该索引为非法索引。

package com.jiangxian.Exception_;

/**
 * @author JiangXian~
 * @version 1.0
 */
public class ArrayIndexOutOfException_ {
    public static void main(String[] args) {
        int[] a = new int[5];
        System.out.println(a[5]);
    }
}

ClassCastException:

当试图将对象强制转换为不是实例的子类时,抛出该异常。

package com.jiangxian.Exception_;

/**
 * @author JiangXian~
 * @version 1.0
 */
public class ClassCastException {
    public static void main(String[] args) {
        A a = new B(); // 向上转型
        B b = (B)a; // 向下转型,ok
        C c = (C)a; // 不行
    }
}

class A{}
class B extends A{}
class C extends A{}

NumberFormatException:

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,会抛出异常。

例子就是英文不能作为数字输出。

package com.jiangxian.Exception_;

/**
 * @author JiangXian~
 * @version 1.0
 */
public class NumberFormatException {
    public static void main(String[] args) {
        String name = "JiangXian";
        int num = Integer.parseInt(name);
        System.out.println(num);
    }
}

小结一些我的发现:

这些异常,都是会被标注为黄色的Warning,我们可以无视它运行程序(但是程序可能会报错)。

所以运行异常会被标注为黄色的Warning;但是并不是所有的黄色Warning都是运行异常!

其能够通过编译,但是运行不能成功。


编译异常:

编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译。(你可以去终端中尝试 javac 编译一下,发现,运行异常,是会正常生成字节码文件.class的,但是编译异常是生成不了的,还会报错)。

常见的编译异常:

一般发生在,网络、文件、数据库操作的情况。

  1. SQLException——操作数据库时,查询表可能发生异常;
  2. IOException——操作文件时,发生的异常;
  3. FileNotFoundException——当操作一个不存在的文件时,发生异常;
  4. ClassNotFoundException——加载类,而该类不存在时,异常;
  5. EOFException——操作文件,到文件末尾,发生异常;
  6. IllegalArguementException——参数异常。

异常处理:

基本介绍:

异常处理就是当异常发生时,对异常处理的方式;

异常处理的方式:

  1. try-catch-finally:程序员在代码中捕获发生的异常,自行处理。
  2. throws:将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM。

try-catch-finally:

java中提供 trycatch块来处理代码。

catch块——用于处理 try 中发生地异常。

根据需求在程序中可以有多个 try…catch块。

处理机制:

try{
    代码/可能有异常
}catch(Exception e){
    // 捕获到异常:
    // 1.当异常发生时;
    // 2.系统将异常封装为Exception 对象 e,传递给 catch;
    // 3.得到异常对象后,程序员,自行处理;
    // 4.注意若没有异常,catch 代码块不执行
    代码块
}fianlly{
    // 1.不管是否有异常发生,始终要执行finally;
    // 2.所以,通常将释放资源的代码,放在finally中。
    代码块
}

细节:

  1. 若异常发生了,那么异常发生后面地代码不会执行,直接进入到 catch 块;

  2. 若异常没有发生,则顺序执行 try 代码块,不会进入到 catch;

  3. 若希望不管是否发生异常,都执行某段代码(关闭连连接,释放资源),则使用 finally{}代码块;

  4. 可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception 在后,NullPointException 在前),若发生异常,指挥匹配一个catch;

    package com.jiangxian.exception_;
    
    public class try_catch_detail {
        public static void main(String[] args) {
            // 解读:
            // 1. 若try代码块可能有多个异常
            // 2.可以用多个catch去捕获不同的异常
            // 3.要求子类异常在前,父类异常写在后面
            try{
                Person person = new Person();
                person = null;
                System.out.println(person.getage()); // NullPointException
                int n1 = 10;
                int n2 = 0;
                int res = n1 / n2; // ArithmaticException
            }catch(NullPointerException e){
                System.out.println("空指针异常:" + e.getMessage());
            }catch(ArithmeticException e){
                System.out.println("算数异常:" + e.getMessage());
            }catch(Exception e){
                System.out.println(e.getMessage());
            }
        }
    }
    
    class Person{
        int age = 10;
        public int getage(){
            return age;
        }
    }
    
    
  5. 可以进行 try-finally 配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉/退出。应用场景——执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。

    package com.jiangxian.exception_;
    
    public class tryCatchDetail {
        public static void main(String[] args) {
            try{
                int n1 = 10;
                int n2 = 0;
                int res = n1 / n2;
            }finally{
                System.out.println("程序继续运行...");
            }
        }
    }
    // 由于没有进行任何的处理,所以实际上时JVM进行的异常处理,在终端会直接报错。
    
  6. 当 catch 和 finally 都有return的时候,若捕获到异常,先执行 catch 中的 return 语句,但暂时不返回,返回的是finally中的 return 语句中的结果(catch 的语句执行但不返回,返回的是 finally 中 的renturn);

  7. 当 finally 无 return,但catch 中有return时,先执行catch 中的return 语句,但暂时不执行,然后执行 finally 中的语句,最后回到catch 的语句执行返回。(如 catch 中是 return i; 但是 finally 中有个++i,那么在第一次遇到return 语句的时候,会有个temp变量暂存i,执行完++i操作后,回到catch 中的return 语句是,将temp 的值重新赋值给i,再返回)。

Exercise:

要求输入字符串,判断是不是整数,不是就一直输入,直到是整数为止。

throws(抛出):

基本介绍:

  1. 若一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表面该方法将不对这些异常进行处理,而是由方法的调用者负责处理

  2. 在方法声明中throws语句可以声明抛出异常的列表(可以抛出多个种类的异常),throws后面地异常类型可以是方法中产生地异常类型,也可以是它的父类。

    package com.jiangxian.exception_.throws_;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    public class Throws01 {
        public static void main(String[] args) {
            
        }
        
        public void f1() throws FileNotFoundException,NullPointerException/*写成Exception即它的父类也可以*/ {
            // 创建了一个文件流对象
            // 这是一个编译时异常,必须处理
            // 1.可以使用try-catch
            // 2.使用throws,明确抛出异常,让调用f1方法的调用者处理
            // 3.throws后也可以是异常列表(也可以用一个Exception代替是所有的)
            FileInputStream fis = new FileInputStream("d://aa.txt");
        }
    }
    
    

处理机制:

  1. try-catch-finally 和 throws 二选一;
  2. 若程序员,没有显示地处理异常,默认采用throws。

模拟流程:

JVM -》调用 main -》调用 f1 -》调用f2(此处发生异常);

f2(抛出异常)-- throws(当也可以时try-catch)-》f1– throws(也可以try-catch)-》main–throws(try-catch)-》JVM。

throws 实际上就是 当前不想处理,返回给上级,让上级去处理,若都不处理,那么最高级JVM处理异常机制特别暴力,其会输出异常并退出程序。

细节:

  1. 对于编译异常,程序中必须处理,比如 try-catch 或 throws;

  2. 对于运行时异常,程序中若没有处理,默认就是 throws的方法;

    public class ThrowsDetails {
        public static void main(String[] args) {
    
        }
    
        public static void f1() /*默认有 throws ArithmeticExpection*/{
            int n1 = 10;
            int n2 = 0;
            int res = n1/n2;
        }
    }
    
  3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类异常的子类;

    class Father{
        void method() throws RuntimeException{}
    }
    
    class Son extends Father{
        // 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,
        //      所重写的异常类型需要是父类的异常或是父类异常的子类
        @Override
        public void method() throws NullPointerException /*换成Exception就不行了*/{
        }
        // 在方法的访问范围,子类可以扩展(业务方面,儿子可以做大做强),但是在异常上,子类只能缩小(儿子犯的错得要是老子能解决的)
    }
    
  4. 在 throws 过程中,若有 try-catch,相当于处理异常,不用再throws了。


自定义异常:

基本概念:

当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类的描述中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。

自定义异常的步骤:

  1. 定义类:自定义异常类型的类名(程序员自己写)继承Exception或RuntimeException;
  2. 若继承Exception则为编译异常;
  3. 若继承RuntimeException,则为运行异常(一般来说继承这个)。
    1. 好处是,我们可以使用默认的处理机制;
    2. 否则我们需要显式地处理。
package com.jiangxian.Exception_.customException;

/**
 * @author JiangXian~
 * @version 1.0
 */
public class CustomException_ {
    public static void main(String[] args) {
        int age = 121;
        if(!(age >= 18 && age <= 120)){
            throw new ArithmeticException("年龄需要在 18~120之间。");
        }
        System.out.println("你的年龄范围正确。");
    }
}

class AgeException extends RuntimeException{
    public AgeException(String message) { // 构造器
        super(message);
    }
}


throw VS throws:

意义位置后面跟的东西
throws异常处理地一种方式方法声明处异常类型
throw手动生成异常对象地关键字方法体中异常对象

Homework:

package com.jiangxian.Exception_.homework;
import java.util.Scanner;

/**
 * @author JiangXian~
 * @version 1.0
 */
public class Homework01 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while(true){
            try{
                System.out.println("请输入第一个整数");
                String n1 = scanner.next();
                int num1 = Integer.parseInt(n1);

                System.out.println("请输入第二个整数");
                String n2 = scanner.next();
                int num2 = Integer.parseInt(n2);
                System.out.println(cal(num1,num2));
                break;
            }catch (NumberFormatException e){
                System.out.println("输入的数不是整数,请重新输入...");
            }catch(ArithmeticException e){
                System.out.println("你输入的除数为0...");
            }
        }
    }

    public static double cal(int n1, int n2){
        return n1 / n2;
    }
}

(459/910)

不知不觉已经学完一半啦,比我预想的慢一点~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江弦凤歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值