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) throws
            InsufficientFundsException {
        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
InsufficientFundsException
        at CheckingAccount.withdraw(CheckingAccount.java:25)
        at BankDemo.main(BankDemo.java:13)

多线程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/633226.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

55. UE5 RPG 处理当前功能在多人模式中的问题

在UE里面&#xff0c;我们运行项目可以设置多种网络模式&#xff0c;主要是分为三种&#xff1a; 运行Standalone 就是单人模式&#xff0c;没有网络交互以监听服务器运行&#xff0c;在界面里运行的游戏会作为服务器使用以客户端运行&#xff0c;UE会单独运行一个线程作为服务…

面向对象-----继承

前面向大家介绍了面向对象中的封装性&#xff0c;今天再来向大家介绍面向对象的继承和多态的两大特性。 1.继承 1.1 为什么需要继承&#xff1f; 在java语言中&#xff0c;我们用类来描述世间万物&#xff0c;虽然万物非常复杂&#xff0c;但总有一些共同点&#xff0c;如果…

深入Django项目实战与最佳实践

title: 深入Django项目实战与最佳实践 date: 2024/5/19 21:41:38 updated: 2024/5/19 21:41:38 categories: 后端开发 tags: Django 基础项目实战最佳实践数据库配置静态文件部署高级特性 第一章&#xff1a;Django项目架构与设计原则 Django框架概述 Django是一个高级的P…

linux的用户管理

新建用户&#xff1a;1.useradd 2.passwd 完成的操作&#xff1a; (1)/etc/passwd添加一行 (2)/etc/shadow添加一行 (3)/etc/group添加一行 (4)创建用户家目录 (5)创建用户邮件文件 例&#xff1a;创建用户jerry&#xff0c;要求: uid:777&am…

文心一言指令解析

1、介绍 文心一言是一款灵感启发类的产品&#xff0c;它以简洁而深刻的文字表达来激发读者的思考和感悟。该产品通过每天提供一句精选的短语&#xff0c;让用户在繁忙的生活中停下脚步&#xff0c;思考人生和内心的真实需求。 每一句文心一言都经过精心挑选&#xff0c;它们通…

苹果MacOS系统使用微软远程桌面连接Windows电脑桌面详细步骤

文章目录 前言1. 测试本地局域网内远程控制1.1 Windows打开远程桌面1.2 局域网远程控制windows 2. 测试Mac公网远程控制windows2.1 在windows电脑上安装cpolar2.2 Mac公网远程windows 3. 配置公网固定TCP地址 前言 日常工作生活中&#xff0c;有时候会涉及到不同设备不同操作系…

【SpringBoot】整合百度文字识别

流程图 一、前期准备 1.1 打开百度智能云官网找到管理中心创建应用 全选文字识别 1.2 保存好AppId、API Key和Secret Key 1.3 找到通用场景文字识别&#xff0c;立即使用 1.4 根据自己需要&#xff0c;选择要开通的项目 二、代码编写 以通用文字识别&#xff08;高精度版&am…

2024-5-4-从0到1手写配置中心Config之基于h2的config-server

添加依赖 新建的web工程中添加h2的依赖 添加h2的配置 设置数据源和密码设置初始化sql语句打开h2的控制台 初始化语句创建一个config表&#xff0c;保存服务配置信息。 完成CRUD接口 controller类 mapper接口 测试 在web控制台可以看到sql已经初始化完成&#xff0c;crud接口…

如何*永久*禁用edge打开PDF文件?

要永久禁用Microsoft Edge打开PDF文件&#xff0c;您可以按照以下步骤进行操作&#xff1a; 打开文件资源管理器并找到任意一个PDF文件。 右键单击该文件并选择“属性”。 在“属性”对话框中&#xff0c;单击“更改”按钮旁边的“打开方式”。 在“打开方式”对话框中&…

Leetcode - 398周赛

目录 一&#xff0c;3151. 特殊数组 I 二&#xff0c;3152. 特殊数组 II 三&#xff0c;3153. 所有数对中数位不同之和 四&#xff0c;3154. 到达第 K 级台阶的方案数 一&#xff0c;3151. 特殊数组 I 本题就是判断一个数组是否是奇偶相间的&#xff0c;如果是&#xff0c;…

【Floodfill算法】dfs或者bfs解决floodfill算法

1.图像渲染 图像渲染 dfs解决代码&#xff1a; class Solution { public:int dx[4] {0, 0, -1, 1};int dy[4] {-1, 1, 0, 0};int m, n;int prev;vector<vector<int>> ret;vector<vector<int>> floodFill(vector<vector<int>>& ima…

Java并发: 锁和同步

在Java并发: 面临的挑战那一篇中我们提到锁和同步是实现并发安全(可见性/原子性)的方法之一。这一章我们来讲讲Java中的锁和同步的各种工具&#xff0c;包括: LockSupportAbstractQueuedSynchronizerJava内置的锁实现 1. LockSupport LockSupport是基于Unsafe的park/unpark实…

linux 查看java线程与linux线程关系

linux 查看占用cpu高的 java 线程 linux 排查cpu占用100%故障 ##java程序 import java.util.Scanner; public class JavaThreadIDName {public static void main(String[] args) {Thread t Thread.currentThread();t.setName("laoyoutiao");System.out.println(&…

golang创建式设计模式---工厂模式

创建式设计模式—工厂模式 目录导航 创建式设计模式---工厂模式1)什么是工厂模式2)使用场景3)实现方式4)实践案例5)优缺点分析 1)什么是工厂模式 工厂模式(Factory Method Pattern)是一种设计模式&#xff0c;旨在创建对象时&#xff0c;将对象的创建与使用进行分离。通过定义…

以太坊(2)——共识机制与挖矿算法

共识机制 ETH采用的是基于GHOST协议的共识机制 "GHOST"&#xff08;Greedy Heaviest-Observed Sub-Tree&#xff09;共识机制&#xff0c;它是以太坊使用的一种改进的区块链共识算法。GHOST共识机制旨在提高链的安全性和效率&#xff0c;通过考虑非主链区块的贡献&…

kubectl详解

文章目录 kubectl详解一、陈述式管理1、陈述式资源管理方法2、k8s相关信息查看2.1 查看版本信息2.1.1 查看资源对象简写2.1.2 查看集群信息2.1.3 配置kubectl自动补全2.1.4 查看日志 2.2 基本信息查看2.2.1 查看集群状态2.2.2 查看命名空间 2.3 命名空间操作2.3.1 查看default命…

CDN用户平台安装说明

CDN用户平台安装说明 登录管理员系统 在”系统设置” – “高级设置” – “用户节点”中点击”添加节点” 如果所示&#xff1a; 节点名称 - 可以任意填写 进程监听端口 - 启动用户节点后&#xff0c;进程所监听的端口&#xff0c;通常是HTTP 80或者HTTPS 443&#xff0c;…

html 段落与排版标记 Web前端开发技术、详细文章(例如)

段落与排版标记 网页的外观是否美观&#xff0c;很大程度上取决于其排版。在页面中出现大段的文字&#xff0c;通常采用分段进行规划&#xff0c;对换行也有极其严格的划分。本节从段落的细节设置入手&#xff0c;利用段落与排版标记自如地处理大段的文字。 段落p标记 在HTM…

Spring Cloud Gateway 网关

一. 什么是网关&#xff08;Gateway&#xff09; 网关就是一个网络连接到另一个网络的关口。 在同一个项目或某一层级中&#xff0c;存在相似或重复的东西&#xff0c;我们就可以将这些相似重复的内容统一提取出来&#xff0c;向前或向后抽象成单独的一层。这个抽象的过程就是…

Linux磁盘高级操作

RAID RAID存储系统是一种数据存储虚拟化技术&#xff0c;它将多个物理磁盘驱动器组合成一个或多个逻辑单元&#xff0c;以提供数据冗余和/或提高性能。 1. RAID 0 无奇偶校验与冗余&#xff08;磁盘容错&#xff09;的条带存储&#xff08;带区卷/条带卷&#xff09; 由两块…