当前位置: 首页 > news >正文

05 JavaSE-- 异常、IOStream、多线程、反射、Annotation、泛型、序列化

Exception 异常

  • 异常也是对象,也有自己的体系,在这个体系中,所有异常对象的根类是 throwable 接口。
  • 异常和 error 错误是不同的概念。
    错误是严重的 JVM 系统问题,一般不期待程序员去捕获、处理这些错误,同时,也不应期待程序不会从错误中恢复。
    当发生错误时,通常意味着应用程序已经无法正常执行,最好的做法是记录错误信息然后终止程序。
    在这里插入图片描述
  • Java 提供了以下关键字和类来支持异常处理:
    • try:用于包裹可能会抛出异常的代码块。
    • catch:用于捕获异常并处理异常的代码块。
    • finally:用于包含无论是否发生异常都需要执行的代码块。
    • throw:用于手动抛出异常。
    • throws:用于在方法声明中指定方法可能抛出的异常。
    • Exception 类:是所有异常类的父类,它提供了一些方法来获取异常信息,如 getMessage()、printStackTrace() 等。
  • 在 Java 中,异常分为两种:
    • Checked Exceptions 检查(强制)性异常:必须提前在代码中处理的异常,如果不处理编译器报错。
    • Unchecked / RunTime Exceptions 非检查性(运行时)异常:可以在代码中选择性处理的异常,即使不处理也能不报错编译通过

1. Checked Exceptions 检查性/强制性/编译时异常

  • 强制性异常是由编译器检查到的异常
  • 强制性异常必须提前在程序中写好代码处理。要么通过 try-catch语句捕获,要么通过方法签名声明抛出。
  • 强制性异常通常是由外部因素引起的,例如文件不存在、网络连接中断等。
  • 强制性异常必须在代码中显式处理,要么通过 try-catch 块捕获并处理,要么通过在方法签名中使用 throws 关键字声明该异常,以通知调用者处理。
try {// 可能会抛出 IOException 的代码
} catch (IOException e) {// 处理 IOException
}
public void readFile() throws IOException {// 可能会抛出IOException的代码
}

2. Unchecked / RunTime Exceptions 非检查性(运行时)异常

  • 运行时异常是在运行时抛出的异常
  • 运行时异常无需提前在程序中设置捕获语句进行处理。
  • 运行时异常通常是由程序内部错误引起的,例如空指针引用、数组越界等。
  • 运行时异常通常是由程序员在编写代码时可以避免的,因此也称为“非强制性”异常。

3. 处理异常

  • 异常的处理包括两种方式:
    • 声明异常:类似于推卸责任的处理方式
      在方法定义时使用 throws 关键字声明异常,告知调用者,调用这个方法可能会出现异常,但自身并不处理。这种处理方式的态度是:如果出现了异常则会抛给调用者来处理。
    • 捕获异常:真正的处理
      在可能出现异常的代码上使用 try-catch 进行捕获处理。这种处理方式的态度是:把异常抓住。

4. 手动抛出异常 throw

  • 程序在运行中检测到错误后,可以创建一个合适类型的异常实例并抛出它
  • 在同一方法内先用 throw 抛出异常,再用 try-catch 捕获没有任何作用。正确的做法是调用该方法的方法内,用try-catch 捕获
  • 手动抛出的异常有两种, 分别为运行时异常和编译时异常.、
    • 抛出运行时异常时,可以不用处理抛出的这个异常.
    • 抛出编译时异常时,必须要处理抛出的这个异常,否则编译不能通过
/** divide 方法内部检查了除数是否为 0,如果是,则使用 throw 关键字抛出一个 ArithmeticException。- 调用这个方法的代码块通过 try-catch 捕获了这个异常,并在 catch 块中处理了这个错误情况*/ public static double divide(double chushu, double beichushu) throws ArithmeticException {// 事实上,即使不手动抛出,JVM 也会检测到该运行时异常,自动抛出// 因此下面三行代码有没有,输出结果都一样if (beichushu == 0) {throw new ArithmeticException("除数不能为零");}return beichushu / chushu;}public static void main(String[] args) {try {double result = divide(10, 0);System.out.println("结果是: " + result);} catch (ArithmeticException e) {System.err.println("发生错误: " + e.getMessage());}}

在这里插入图片描述

public class ThrowEx {// 手动抛出运行时异常,可以不处理public void setAge(int age) {if (age < 0) {throw new NullPointerException("输入的年龄小于0");}}// 手动抛出编译时异常,调用该方法者必须要处理这个异常public void setAge2(int age) throws FileNotFoundException {if (age < 0) {throw new FileNotFoundException("输入的年龄小于0");}}public static void main(String[] args) {ThrowEx throwEx = new ThrowEx();// 首先明确,尽管方法 1, 2 都抛出了异常,但在调用方法种,并没有处理抛出的异常//方法 1 指定的异常是运行时异常,调用者不是必须处理这个异常,编译也能通过//方法 2 指定的异常是编译时异常,由于调用者没有处理,因此无法编译通过throwEx.setAge(-5);//throwEx.setAge2(-5);}

调用方法 1 时,正常编译构建,并送出错误提示
在这里插入图片描述
调用方法 2 时,无法通过编译构建
在这里插入图片描述
同时调用方法1,2时,依然无法通过编译构建,这验证了之前说过的话:抛出编译时异常时,必须要处理抛出的这个异常,否则编译不能通过。

5. 自动捕获异常 try-catch-finally

  • 使用 try-catch-finally 处理编译时异常,是让程序在编译时就不再报错,但是运行时仍然有可能报错。相当于我们使用 try-catch 将一个编译时可能出现的异常,延迟到运行时出现。
  • 在开发中,运行时异常比较常见,此时一般不用 try-catch 去处理,因为处理和不处理都是一个报错,最好办法是去修改代码。
  • try 和 catch 必须配对使用,finally 则没有强制要求
  • try 语句块中:放的是可能出现问题的代码,尽量不要把不相关的代码放入到里面,否则会出现截断的问题。
  • catch 括号中,声明想要捕获的异常类型;语句块中,放置捕获指定异常后处理问题的代码,如果问题在 try 语句块中没有出现,则 catch 不会运行。
  • finally 语句块中:放的是不管问题异常是否产生,都要执行的代码。
/**Integer.parseInt(str)方法将 str 转换为整数。但由于str的内容不是有效的整数(它包含字母而非数字),- 这个操作将会抛出一个 NumberFormatException。- catch 括号中声明本次捕获目标是 NumberFormatException,如果发生此异常,将执行该块中的代码,即 e.printStackTrace()。- 第二个 catch 括号中声明本次捕获目标是 Exception,由于 Exception 本就是所有异常的根类- 因此第二个 catch 可以捕获除 NumberFormatException 之外的所有异常类型(前提是这些异常没有在第一个 catch 块中被捕获)。- 这里,如果捕获到任何其他异常,程序将输出e.getMessage(),即异常的描述信息。- finally块:无论是否发生异常,finally块中的代码都会被执行。*/public static void main(String[] args) {String str = "avocado";try {int i = Integer.parseInt(str);} catch (NumberFormatException e) {e.printStackTrace();} catch (Exception e) {System.out.println(e.getMessage());} finally {System.out.println("运行完毕");}}

在这里插入图片描述

6. 声明异常 throws

  • 在 Java 中,当前执行的语句必属于某个方法。
  • 每个方法都必须声明它可能抛出的强制性异常的类型。
  • 声明的方式是:在方法头使用 throws 关键字
public void myMethod throws Exceptionl, Exception2,… ,ExceptionN
  • throws 一般用于方法中可能存在异常时,需要将异常情况向方法之上的层级抛出,由抛出方法的上一级来解决这个问题,如果方法的上一级无法解决的会就会再将异常向上抛出,最终会抛给 main 方法,这样一来 main 方法中调用了这个方法的时候,就需要解决这个可能出现的异常.
    当然 main 方法也可以不解决异常,将异常往上抛给 JVM ,如果 JVM 也无法解决的话,那么 JVM 就 over 了
  • try-catch-fianlly 真正将异常给处理掉了。throws 只是将异常抛给了方法的调用者,并没有真正将异常处理掉。
  • 之前所述,子类重写父类方法时,不可以抛出新的强制性异常,或者比父类方法声明的更广泛的强制性异常。

7. 如何选择 try-catch-finally 和 throws

什么时候捕捉?什么时候声明?
如果异常发生后需要调用者来处理的,需要调用者知道的,则采用声明方式。否则采用捕捉。

  • 同一方法内, try-catch 和 throws 不要同时使用。因为只要 try-catch 就已经将异常处理掉了,再 throws 没有任何意义
  • 放眼整个程序,try-catch 和 throws 应当联合使用。

例如,在方法标签通过 throws 抛出异常,让调用者决定如何处理。而调用者使用 try-catch 捕获并处理这些异常。

  • 如果父类的方法没有声明抛出任何检查型异常(Checked Exception),则子类在重写这个方法时也不能声明抛出检查型异常。因此,如果子类重写的方法中需要处理异常,必须在方法内部使用 try-catch-finally 进行处理。

如果父类的方法没有使用 throws 声明任何检查型异常,意味着该方法不抛出任何需要强制处理的检查型异常。

  • 在一个复杂的调用链中,建议在较底层的方法中使用 throws 抛出异常,而在较高层的方法中使用 try-catch-finally 来处理这些异常。

假设我们有以下方法调用链:
方法 a 调用 方法 b
方法 b 调用 方法 c

在较底层的方法 b、c ,使用 throws 声明这些方法可能抛出的异常,而不在这些方法内部进行异常捕获和处理。这种做法有以下优点:

异常传播:将异常传递给调用者,让调用者决定如何处理。
简化代码:底层方法专注于核心逻辑,不必处理异常,从而简化代码。

public class Example {public static void methodC() throws Exception {if (someCondition) {throw new Exception("Method C exception");}// 方法 C 的其他逻辑}public static void methodB() throws Exception {methodC();// 方法 B 的其他逻辑}public static void methodA() {try {methodB();} catch (Exception e) {System.err.println("发生错误: " + e.getMessage());} finally {System.out.println("清理操作");}}public static void main(String[] args) {methodA();}
}

高层方法使用 try-catch-finally 处理异常

在较高层的方法 a ,使用 try-catch-finally 捕获和处理所有底层方法抛出的异常。这种做法有以下优点:

集中处理:所有异常都在一个地方处理,便于管理和维护。
保证执行:即使发生异常,也可以确保 finally 块中的清理操作能够执行。

为什么要这样做
数据返回问题:如果在方法 b 中使用 try-catch 捕获并处理异常,方法 a 可能无法获得所需的数据。这是因为异常处理可能会中断正常的数据流。
异常聚合:将异常传递到高层方法,允许高层方法集中处理所有可能的异常,提高了代码的可读性和可维护性。

8. 自定义异常类

Java 中允许自定义异常(类)

  • 所有异常都必须是 Throwable 的子类。
  • 如果目标是写一个强制性异常类,则需要继承 Exception 类。
  • 如果目标是写一个运行时异常类,则需要继承 RuntimeException 类。
  • 一个异常类和其它任何类一样,包含有变量和方法。

8.1 自定义异常处理-- 支付余额不足

// 自定义异常类:余额不足
// 继承 Exception 类,该自定义异常是强制性异常,必须在编译之前,由 try-catch 捕获
public class InsufficientFundsException extends Exception
{//balanceShortage 储存当出现异常(取出钱多于余额时)所缺乏的钱private double balanceShortage;public InsufficientFundsException(double balanceShortage){this.balanceShortage= balanceShortage;} public double getBalanceShortage(){return balanceShortage;}
}
//此类模拟银行账户
public class Account {
// 区分异常类,此处的 balance 就是单纯的余额private double balance;private int cardNum;public Account (int cardNum) {this.cardNum = cardNum;}//方法:存钱public void deposit(double amount) {balance += amount;}//方法:取钱public void withdraw(double amount) throwsInsufficientFundsException {if (amount <= balance) {balance -= amount;} else {double needs = amount - balance;throw new InsufficientFundsException(needs);}}//方法:返回余额public double getBalance() {return balance;}//方法:返回卡号public int getCardNum() {return cardNum;}
}
public class BankDemo
{public static void main(String [] args){Account account = new Account(101);System.out.println("Depositing $500...");account.deposit(500.00);try{System.out.println("\nWithdrawing $100...");account.withdraw(100.00);System.out.println("\nWithdrawing $600...");account.withdraw(600.00);}catch(InsufficientFundsException e){System.out.println("Sorry, but you are short $"+ e.getBalanceShortage());e.printStackTrace();}}
}

输出为 :

Depositing $500...Withdrawing $100...Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsExceptionat CheckingAccount.withdraw(CheckingAccount.java:25)at BankDemo.main(BankDemo.java:13)

多线程

http://www.lryc.cn/news/350747.html

相关文章:

  • c++/c语法基础【2】
  • python 庆余年2收视率数据分析与可视化
  • yolov8训练自己数据集时出现loss值为nan。
  • [Chapter 5]线程级并行,《计算机系统结构》,《计算机体系结构:量化研究方法》
  • 首发!飞凌嵌入式FETMX6ULL-S核心板已适配OpenHarmony 4.1
  • Power BI实现动态度量值
  • 给大家分享一套非常棒的python机器学习课程
  • 免费,Python蓝桥杯等级考试真题--第6级(含答案解析和代码)
  • Spring Boot:SpringBoot 如何优雅地定制JSON响应数据返回
  • c++中的constexpr 与decltype
  • 苹果MacOS系统使用微软远程桌面连接Windows电脑桌面详细步骤
  • 【paper】基于分布式采样的多机器人编队导航信念传播模型预测控制
  • 代码随想录算法训练营第二天| 977.有序数组的平方 、209.长度最小的子数组、 59.螺旋矩阵II
  • list stream 改变list属性的值
  • 绿色智能:AI机器学习在环境保护中的深度应用与实践案例
  • Java高级面试精粹:问题与解答集锦(二)
  • 基于机器学习模型预测信用卡潜在用户(XGBoost、LightGBM和Random Forest)
  • java 通过 microsoft graph 调用outlook(三)
  • QT--TCP网络通讯工具编写记录
  • 如何解决爬虫的IP地址受限问题?
  • harmony 文件上传
  • 什么是安全左移如何实现安全左移
  • 将PCD点云投影到BEV平面得到图片
  • 计算机笔记14(续20个)
  • docker 使用桥接网
  • 1金融风控相关业务介绍
  • 521源码-免费教程-经常用到的Vue.js的Vue@Cli入门指导
  • 大数据技术原理(二):搭建hadoop伪分布式集群这一篇就够了
  • 中间件是什么?信创中间件有哪些牌子?哪家好用?
  • python实现520表白图案