目录

前言

引入:

一 、异常

1.异常是什么?(what)

2.异常的代表是谁?分为几类?

3.异常的作用是啥?

二 、运行异常

一、数组越界异常

二、空指针异常

三、算术异常

四、类型转换异常

三 、编译异常

​编辑

四 、异常处理

1.throws抛出

2.try -catch

3.throw关键字抛出

​编辑

 4.try-catch-fianlly

四、自定义异常

继承自 Exception 的异常默认是受查异常

继承自 RuntimeException 的异常默认是非受查异常

异常处理关键字横向对比表

总结



前言

今天我们来学习异常的相关内容


引入:

Java异常分两种情况——编译异常与运行异常。

运行异常(Runtime Exception)
乐锅一个朋友没有带钱去KFC,他可以坐在那里吹空调,但不能点餐。因为他没有带钱,点餐会扣他的钱包里面的钱,而他没得扣,如果强行点餐,会报错误。

编译异常(Checked Exception)
乐锅一个朋友前些天在下载某些软件时候。系统会弹出红色警告。而他选择无视风险,继续安装。这就是运行异常。

一 、异常

1.异常是什么?(what)

异常是代码在编译或者执行的过程中可能出现的错误。

2.异常的代表是谁?分为几类?

Exception,分为两类:编译时异常、运行时异常。

编译时异常:没有继承RuntimeExcpetion的异常,编译阶段就会出错。

运行时异常:继承自RuntimeException的异常或其子类,编译阶段不报错,运行时出现的。

3.异常的作用是啥?

用来查找bug;可以作为方法内部的特殊返回值,通知上层调用者底层的执行情况。

二 、运行异常

1.数组越界异常

当访问数组中不存在的索引时触发该异常。

代码示例

public class Example {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        // 尝试访问索引为3的元素(数组最大索引为2)
        int num = arr[3];
        System.out.println(num); // 此处会抛出异常,程序终止
    }
}

报错(异常):

2.空指针异常

当调用一个为null的对象的方法或属性时触发该异常。

代码示例

public class Example2 {
    public static void main(String[] args) {
        String str = null;
        // 尝试调用null对象的length()方法
        int len = str.length();
        System.out.println(len); // 抛出NullPointerException
    }
}

报错(异常):

3.算术异常

场景描述:数学运算错误,例如除以零。

代码示例

public class ArithmeticExceptionExample {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        // 尝试除以零
        int result = a / b;
        System.out.println(result); // 抛出ArithmeticException
    }
}

报错(异常):

4.类型转换异常

场景描述:尝试将对象强制转换为不兼容的类型时触发。

代码示例

public class ClassCastExceptionExample {
    public static void main(String[] args) {
        Object obj = "Hello"; // 字符串对象
        // 强制转换为Integer类型
        Integer num = (Integer) obj; // 抛出ClassCastException
    }
}

报错(异常):


三 、编译异常

写完代码后会红色报错,且运行不了

四 、异常处理

这个时候我们鼠标放在红色代码上按alt键,就会出现两种异常处理

分别是try catch 和添加异常到方法的throws(抛出)

1.throws抛出

在方法增加throws Exception

方法一:throws 抛出    
public static void main(String[] args) throws InterruptedException {
        // Thread.sleep 抛出的是 InterruptedException(受检异常)
        Thread.sleep(1000);
        System.out.println("Done");
    }
}

//我们可以把抛出Exception前面的类型删掉,这样可以让我们面对多个异常的时候只用抛出一次
public static void main(String[] args) throws Exception {
        // Thread.sleep 抛出的是 InterruptedException(受检异常)
        Thread.sleep(1000);
        System.out.println("Done");
    }
}

2.try -catch

try {

// 可能抛出异常的代码

} catch (Exception e) {

e.printStackTrace();// 打印异常信息

}

   public static void main(String[] args)  {
        // Thread.sleep 抛出的是 InterruptedException(受检异常)
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("Done");
    }
}

所以我们可以改成这样:

把Exception前面内容删掉,然后调用e.printStackTrace方法,如果不通过则打印异常信息

    public static void main(String[] args)  {
        // Thread.sleep 抛出的是 InterruptedException(受检异常)
        try {
            Thread.sleep(1000);
            System.out.println("Done");
        } catch (Exception e) {
           e.printStackTrace();
        }
    }
}

3.throw关键字抛出

    public static void main(String[] args) {
            saveAge(300);
        System.out.println("程序结束。。。。");
    }

    // 需求:我们公司的系统只要收到了年龄小于1岁或者大于200岁就是一个年龄非法异常。
    public static void saveAge(int age) {
        if(age < 1 || age > 200){
            // 年龄非法;抛出去一个异常。
            //在这里自己手动抛出异常,而不是jvm的异常
            throw new myselfException2("年龄非法 age 不能低于1岁不能高于200岁");
        }else {
            System.out.println("保存年龄:" + age);
        }
    }
}

 4.try-catch-fianlly

finally:无论如何都会最后执行

不过我们常用于io流是释放资源,比如关闭文件、释放数据库连接、关闭网络连接等。确保这些资源在使用后能够被正确释放,以避免资源泄漏。

同时我们也会遇到没跑完就关闭的可能性,这里我们后面会讲到

 public static void main(String[] args) {
            System.out.println("Start");
            try {
                System.out.println("In try");
                int r = 10 / 0; // 会抛出 ArithmeticException(运行时异常)
                System.out.println("After error"); // 不会执行
            } catch (Exception e) {
                System.out.println("In catch: " + e.getClass().getSimpleName() + " - " + e.getMessage());
            } finally {
                System.out.println("In finally: cleanup here");
            }
            System.out.println("End");
        }

四、自定义异常

自定义异常通常会继承自 Exception 或者 RuntimeException


继承自 Exception 的异常默认是受查异常

  • 编译器强制要求:调用者必须通过try-catch捕获或在方法签名中使用throws声明,否则编译失败
  • 设计目的:表示可预见、可恢复的外部问题,调用者有能力或责任采取补救措施


继承自 RuntimeException 的异常默认是非受查异常

  • 编译器不强制要求:调用者可选择处理或忽略,编译器不会报错
  • 设计目的:表示程序逻辑错误或不可恢复的问题,调用者无法合理处理

继承Exception:


//继承Exception
public class myselfException extends Exception{
    public myselfException(String message) {
        System.out.println(message);super(message);
    }
    public myselfException(){

    }
}
    public static void main(String[] args) {
        try {
            show(200);
        } catch (myselfException e) {
            e.printStackTrace();

        }
    }

    private static void show(int age) throws myselfException {
        if(age<1 || age>120){
            throw new myselfException("您输入的年龄有误");
        }else{
            System.out.println("年龄合法,保存");
        }
    }

继承RuntimeEception:

public class myselfException2 extends RuntimeException{
    public myselfException2(String message) {
        System.out.println(message);super(message);
    }
    public myselfException2(){
}}
public static void main(String[] args) {
            saveAge(300);
        System.out.println("程序结束。。。。");
    }

    // 需求:我们公司的系统只要收到了年龄小于1岁或者大于200岁就是一个年龄非法异常。
    public static void saveAge(int age) {
        if(age < 1 || age > 200){
            // 年龄非法;抛出去一个异常。
            throw new myselfException2("年龄非法 age 不能低于1岁不能高于200岁");
        }else {
            System.out.println("保存年龄:" + age);
        }
    }
}

异常处理关键字横向对比表

对比维度 try-catch try-catch-finally throws throw
核心用途 捕获并处理异常 捕获异常 + 确保资源清理 声明方法可能抛出的异常 主动抛出异常对象
语法位置 方法内部代码块 方法内部代码块 方法签名(参数列表后) 方法内部任意位置
强制性 编译异常必须处理 非强制,但推荐用于资源管理 编译异常必须声明或处理 非强制,按需使用
执行时机 运行时 运行时 编译时检查 运行时
典型场景 处理可恢复的业务异常
(如:文件不存在时使用默认配置)
资源操作必须清理
(如:文件IO、数据库连接、网络请求)
将异常处理责任转移给调用者
(如:底层DAO方法抛出SQLException)
主动触发异常流程
(如:参数校验失败、业务规则违反)
返回值处理 可在catch中返回默认值或重试结果 finally中的return会覆盖try/catch的return 不影响方法返回值 抛出后方法立即终止,无返回值
资源管理 需手动在catch中清理资源 自动确保 finally 块执行,适合资源清理 不涉及资源管理 需配合try-finally确保资源释放
异常传播 异常被捕获,不向上传播 异常被捕获,不向上传播(除非finally中抛出新异常) 异常向上传播给调用者 异常向上传播给调用者
代码 try{}catch{} try{}catch{}finally{} throws Exceptoion throw 
优势 精准处理特定异常
提供恢复机制
100%确保资源释放
代码健壮性强
清晰声明方法契约
调用者明确知道风险
主动控制异常流程
提前暴露问题
劣势 可能过度处理异常
代码嵌套过深
语法相对繁琐
finally中return会覆盖结果
调用者必须处理
可能污染调用链
滥用会导致流程混乱
性能开销较大
设计哲学 防御式编程
"我能处理这个问题"
负责任的清理
"无论如何都要收拾干净"
契约式设计
"这可能会出问题,你得知道"
主动防御
"这里有问题,立刻停止"
前言场景映射 "可以但有警告"的应对方案
(点击继续后处理磁盘不足)
"可以但有警告"的安全保障
(即使失败也释放内存)
"不可但无警告"的责任转移
(灰色按钮的责任说明)
"不可但无警告"的主动拒绝
(直接阻止非法操作)

总结

今天我们学习了异常的相关知识。如何处理异常是Java的一个重点知识。

本次分享到此结束,感谢大家的观看与支持!如果本内容对您有帮助,欢迎点赞、收藏,您的支持将是我持续创作的最大动力,谢谢!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐