JavaSE笔记——异常、断言

news2024/11/26 8:40:30

文章目录

  • 前言
  • 一、处 理 错 误
    • 1.异常分类
    • 2.声明受查异常
    • 3.如何抛出异常
    • 4.创建异常类
  • 二、捕获异常
    • 1.捕获异常
    • 2.捕获多个异常
    • 3.再次抛出异常与异常链
    • 4.finally 子句
    • 5.带资源的 try 语句
  • 三、使用断言
    • 1.断言的概念
    • 2.启用和禁用断言
    • 3.使用断言完成参数检查
  • 总结


前言

在现实世界中却充满了不良的数据和带有问题的代码,现在是讨论 Java 程序设计语育处理这些问题的机制的时候了。对于异常情况, 例如, 可能造成程序崩溃的错误输入,Java 使 用 一 种 称 为 异 常 处 理
( exception handing) 的错误捕获机制处理。Java 中的异常处理与 C++ 或 Delphi 中的异常处理十分类似。


一、处 理 错 误

假设在一个 Java 程序运行期间出现了一个错误。这个错误可能是由于文件包含了错误信息,或者网络连接出现问题造成的,也有可能是因为使用无效的数组下标, 或者试图使用一个没有被赋值的对象引用而造成的。用户期望在出现错误时, 程序能够采用一些理智的行为。如果由于出现错误而使得某些操作没有完成, 程序应该:

  1. 返回到一种安全状态,并能够让用户执行一些其他的命令;
  2. 允许用户保存所有操作的结果,并以妥善的方式终止程序;

要做到这些并不是一件很容易的事情。其原因是检测(或引发)错误条件的代码通常离那些能够让数据恢复到安全状态, 或者能够保存用户的操作结果, 并正常地退出程序的代码很远。异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器。

1.异常分类

在 Java 程序设计语言中, 异常对象都是派生于 Throwable 类的一个实例。如果 Java 中内置的异常类不能够满足需求,用户可以创建自己的异常类。

在这里插入图片描述
需要注意的是,所有的异常都是由 Throwable 继承而来,但在下一层立即分解为两个分支:Error 和 Exception。

Error 类层次结构描述了 Java 运行时系统的内部错误和资源耗尽错误。 应用程序不应该抛出这种类型的对象。 如果出现了这样的内部错误, 除了通告给用户,并尽力使程序安全地终止之外, 再也无能为力了。这种情况很少出现。

在设计 Java 程序时, 需要关注 Exception 层次结构。 这个层次结构又分解为两个分支:一个分支派生于 RuntimeException ; 另一个分支包含其他异常。划分两个分支的规则是:由程序错误导致的异常属于 RuntimeException ; 而程序本身没有问题, 但由于像 I/O 错误这类问题导致的异常属于其他异常。

Java 语 言 规 范 将 派 生 于 Error 类 或 RuntimeException 类的所有异常称为非受查( unchecked ) 异常,所有其他的异常称为受查( checked) 异常。编译器将核查是否为所有的受査异常提供了异常处理器

2.声明受查异常

如果遇到了无法处理的情况, 那么 Java 的方法可以抛出一个异常。这个道理很简单:一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误。例如,一段读取文件的代码知道有可能读取的文件不存在, 或者内容为空,因此, 试图处理文件信息的代码就需要通知编译器可能会抛出 IOException 类的异常。

方法应该在其首部声明所有可能抛出的异常。这样可以从首部反映出这个方法可能抛出哪类受査异常。例如,下面是标准类库中提供的 FilelnputStream 类的一个构造器的声明:

public FilelnputStream(String name) throws FileNotFoundException

这个声明表示这个构造器将根据给定的 String 参数产生一个 FilelnputStream 对象,但也有可能抛出一个 FileNotFoimdExc印tion 异常。如果发生了这种糟糕情况, 构造器将不会初始化一个新的 FilelnputStream 对象, 而是抛出一个 FileNotFoundException 类对象。 如果这个方法真的抛出了这样一个异常对象,运行时系统就会开始搜索异常处理器, 以便知道如何处理FileNotFoundException 对象„

在自己编写方法时, 不必将所有可能抛出的异常都进行声明。至于什么时候需要在方法中用 throws 子句声明异常, 什么异常必须使用 throws 子句声明, 需要记住在遇到下面 4 种情况时应该抛出异常:

  1. 调用一个抛出受査异常的方法, 例如, FilelnputStream 构造器。
  2. 程序运行过程中发现错误, 并且利用 throw语句抛出一个受查异常。
  3. 程序出现错误, 例如,a[-1] =0 会抛出一个 ArraylndexOutOffloundsException 这样的非受查异常。
  4. Java 虚拟机和运行时库出现的内部错误。

如果出现前两种情况之一, 则必须告诉调用这个方法的程序员有可能抛出异常。因为任何一个抛出异常的方法都有可能是一个死亡陷阱。 如果没有处理器捕获这个异常,当前执行的线程就会结束。

对于那些可能被他人使用的 Java 方法, 应该根据异常规范( exception specification), 在方法的首部声明这个方法可能抛出的异常。如果一个方法有可能抛出多个受查异常类型, 那么就必须在方法的首部列出所有的异常类。每个异常类之间用逗号隔开。

public class MyAnimation {
    public Image loadlmage(String s) throws FileNotFoundException, EOFException {
        ...
    }
}

总之,一个方法必须声明所有可能抛出的受查异常, 而非受查异常要么不可控制( Error),要么就应该避免发生( RuntimeException)。如果方法没有声明所有可能发生的受查异常, 编译器就会发出一个错误消息。

3.如何抛出异常

假设在程序代码中发生了一些很糟糕的事情。 一个名为 readData 的方法正在读取一个首部具有下列信息的文件:Content-length: 1024

然而,读到 733 个字符之后文件就结束了。我们认为这是一种不正常的情况,希望抛出一个异常。仔细地阅读 Java API 文档之后会发现:EOFException 异常描述的是“ 在输人过程中, 遇到了一个未预期的 EOF 后的信号”。这正是我们要抛出的异常。

    String readData(Scanner in) throws EOFException{
        if (Mn.hasNextQ){
            if (n < len){
                throw new EOFException();
            }
        }
    }

4.创建异常类

在程序中,可能会遇到任何标准异常类都没有能够充分地描述清楚的问题。 在这种情况下,创建自己的异常类就是一件顺理成章的事情了。我们需要做的只是定义一个派生于Exception 的类,或者派生于 Exception 子类的类。

public class FileFormatException extends IOException {

    public FileFormatException() {

    }

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

public class MyAnimation {
    public static void main(String[] args) throws FileFormatException {
        throw new FileFormatException("我是创建异常类");
    }
}

在这里插入图片描述

二、捕获异常

到目前为止, 已经知道如何抛出一个异常。这个过程十分容易。只要将其抛出就不用理踩了。当然, 有些代码必须捕获异常。

1.捕获异常

要想捕获一个异常, 必须设置 try/catch语句块。最简单的 try语句块如下所示:

try {
    code
} catch (ExceptionType e) {
    handlerfor this type
}

如果在 try语句块中的任何代码抛出了一个在 catch 子句中说明的异常类, 那么

  1. 程序将跳过 try语句块的其余代码。
  2. 程序将执行 catch 子句中的处理器代码。

2.捕获多个异常

在一个 try 语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理。可以按照下列方式为每个异常类型使用一个单独的 catch 子句:

        try {
            //code that might throwexceptions
        } catch (FileNotFoundException e) {
            //emergencyactionfor missingfiles
        } catch (UnknownHostException e) {
            //emergency actionfor unknown hosts
        } catch (IOException e) {
            //emergencyactionfor all other I/O problems
        }

异常对象可能包含与异常本身有关的信息。要想获得对象的更多信息, 可以试着使用 e.getHessage() 得到详细的错误信息(如果有的话) 或者使用 e.getClassO.getNameO得到异常对象的实际类型。

在 Java SE 7中,同一个 catch 子句中可以捕获多个异常类型。例如,假设对应缺少文件和未知主机异常的动作是一样的,就可以合并 catch 子句:

        try {
            //code that might throw exceptions
        } catch (FileNotFoundException | UnknownHostException e) {
            //emergency action for missing files and unknown hosts
        } catch (IOException e) {
            //emergency action for all other I / O problems
        }

3.再次抛出异常与异常链

在 catch 子句中可以抛出一个异常,这样做的目的是改变异常的类型: 如果开发了一个供其他程序员使用的子系统, 那么,用于表示子系统故障的异常类型可能会产生多种解释。ServletException 就是这样一个异常类型的例子。执行 servlet 的代码可能不想知道发生错误的细节原因, 但希望明确地知道 servlet 是否有问题。下面给出了捕获异常并将它再次抛出的基本方法:

        try {
            //access the database
        } catch (SQLException e) {
            throw new ServletException("database error: " + e.getMessageO);
        }

4.finally 子句

当代码抛出一个异常时, 就会终止方法中剩余代码的处理,并退出这个方法的执行。如果方法获得了一些本地资源,并且只有这个方法自己知道,又如果这些资源在退出方法之前必须被回收,那么就会产生资源回收问题。

Java 有一种好的解决方案,这就是 finally 子句。下面将介绍 Java 中如何恰当地关闭一个文件。如果使用 Java 编写数据库程序,就需要使用同样的技术关闭与数据库的连接。

不管是否有异常被捕获,finally 子句中的代码都被执行。在下面的示例中, 程序将在所有情况下关闭文件。

InputStream in;
try {
    in = new FileInputStream("");
    //code that might throwexceptions
} catch (IOException e) {
    e.printStackTrace();
    //showerror message
} finally {
    in.close();
}

5.带资源的 try 语句

对于以下代码模式:

open a resource
try {
work with the resource
}
finally {
close the resource
}

假设资源属于一个实现了 AutoCloseable 接口的类,Java SE 7 为这种代码模式提供了一个很有用的快捷方式。AutoCloseable 接口有一个方法:void close() throws Exception

带资源的 try 语句(try-with-resources) 的最简形式为:

try (Resource res = . . .)
{
work with res
}

try块退出时,会自动调用 res.close()。

三、使用断言

在一个具有自我保护能力的程序中, 断言很常用。

1.断言的概念

假设确信某个属性符合要求, 并且代码的执行依赖于这个属性。例如, 需要计算

double y = Math.sqrt(x);

我们确信,这里的 X 是一个非负数值。原因是:X 是另外一个计算的结果,而这个结果不可能是负值;或者 X 是一个方法的参数,而这个方法要求它的调用者只能提供一个正整数。然而,还是希望进行检查, 以避免让“ 不是一个数” 的数值参与计算操作。当然,也可以抛出一个异常:

if (x < 0) throw new 111egalArgumentException(“x < 0”);

但是这段代码会一直保留在程序中, 即使测试完毕也不会自动地删除。如果在程序中含有大量的这种检查,程序运行起来会相当慢。

断言机制允许在测试期间向代码中插入一些检査语句。当代码发布时,这些插人的检测语句将会被自动地移走。

Java 语言引人了关键字 assert。这个关键字有两种形式:

  1. assert 条件;
  2. assert 条件:表达式;

2.启用和禁用断言

在默认情况下, 断言被禁用。可以在运行程序时用 -enableassertions 或 -ea 选项启用:

java -enableassertions MyApp

也可以用选项 -disableassertions 或 -da 禁用某个特定类和包的断言:

java -ea:… -da:MyClass MyApp

3.使用断言完成参数检查

什么时候应该选择使用断言呢? 请记住下面几点:

  1. 断言失败是致命的、 不可恢复的错误。
  2. 断言检查只用于开发和测阶段

因此,不应该使用断言向程序的其他部分通告发生了可恢复性的错误,或者,不应该作为程序向用户通告问题的手段。断言只应该用于在测试阶段确定程序内部的错误位置。


总结

以上就是关于异常和断言的内容,我们应该正确处理程序异常。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

由浅入深学安全-1

由浅入深学安全 常用术语解析 肉鸡 肉鸡也称傀儡机&#xff0c;是指可以被黑客远程控制的机器。 比如用灰鸽子等诱导客户点击或者电脑被黑客攻破或用户电脑有漏洞被种植了木马&#xff0c;黑客可以随意操纵它并利用它做任何事情。 一句话木马 一句话木马主要用来配合菜刀…

【Java系列】还在为Java运算符而烦恼吗?一篇文章带你解答心中烦恼

返回主篇章         &#x1f447; 【Java】才疏学浅小石Java问道之路 Java基本运算符1. 算数运算符分类运算法则2. 关系运算符分类注意项3. 逻辑运算符分类运算法则4. 短路逻辑运算符分类运算法则5. 赋值运算符拓展6. 三元运算符格式运算法则7. 自增自减运算符分类使用…

12-Golang中的嵌套分支以及switch语句的用法

Golang中的嵌套分支以及switch语句的用法嵌套分支基本介绍基本语法switch基本介绍基本语法流程图使用细节嵌套分支 基本介绍 在一个分支结构中又完整的嵌套了另一个完整的分支结构&#xff0c;里面的分支的结构称为内层分支外面的分支结构称为外层分支 基本语法 if 条件表达…

声明式服务调用OpenFeign

文章目录一. OpenFeign1. Feign 与 OpenFeign二. OpenFeign的使用三. OpenFeign自定义配置1. 修改日志级别2. 超时控制四. OpenFeign性能优化五. OpenFeign最佳实践1. 继承2. 抽取PS: 本文为作者学习笔记&#xff0c;实际技术参加意义不大&#xff0c;本文将持续改进完善。 一…

Doris(二)

目录1、Doris数据的导入和导出1.1 数据导入1.1.1 Broker Load1.1.1.1 适用场景1.1.1.2 基本原理1.1.1.3 基本语法1.1.1.4 导入示例1.1.1.5 查看导入1.1.1.6 取消导入1.1.2 Stream Load1.1.2.1 适用场景1.1.2.2 基本原理1.1.2.3 基本语法1.1.2.4 导入示例1.1.2.5 取消导入1.1.3 …

蓝牙耳机什么牌子好?性价比最高的蓝牙耳机排行榜

近年来&#xff0c;蓝牙耳机品牌与日俱增&#xff0c;可供人们选择的范围也越来越大。当然&#xff0c;主打性价比的蓝牙耳机品牌也有很多&#xff0c;下面&#xff0c;我来给大家分享几款性价比最高的蓝牙耳机&#xff0c;一起来看看吧。 一、南卡小音舱蓝牙耳机 售价&#…

寒潮来袭,这款产品在跨境电商市场卖脱销

年底的寒潮来袭&#xff0c;全球市场热销产品分析跨境电商在年底冬季属于销售旺季&#xff0c;大多数的跨境电商卖家们都开始尽情努力&#xff0c;争取今年获得大批收入&#xff0c;在这个年底既是旺季也是困难季。2022年底旺季时分&#xff0c;有不少产品在跨境电商市场卖脱销…

jQuery index()

jQuery index() 概述 在jQuery中&#xff0c;我们可以使用index()方法来获取当前jQuery对象集合中“指定元素”的索引值。 语法 $(元素).index()说明 index()方法可以接受一个“jQuery对象”或“DOM对象”作为参数&#xff0c;不过一般情况下&#xff0c;我们很少会使用到…

Idea常用快捷键(MacOS和Win平台)持续更新ing~

小名在刚换MacOS系统时总结的一些Idea快捷键&#xff0c;这里小名把Win的对比快捷键和功能都列出来&#xff0c;方便像小名这样“肌肉记忆”的小伙伴顺利过渡&#xff5e; 当然&#xff0c;这些都是小名平日工作常用的快捷键&#xff0c;不熟悉这些快捷键的Win平台小伙伴也可以…

springboot的核心注解详解

springboot的注解详解 Spring Boot 主要优势之一&#xff0c;就是“开箱即用&#xff0c;远离繁琐的配置”。 Spring Boot 架构没有代码生成&#xff0c;也不需要XML配置&#xff0c;有效避免大量的 Maven 导入和各种版本冲突&#xff0c;为 Spring 开发提供一个更快、更广泛…

数字ic后端|分享后端项目中一次分析解决问题的过程

后端ICer经常会在项目中遇到问题&#xff0c;如何解决问题&#xff0c;则体现出经验。今天遇到的一个问题&#xff0c;这里做个记录。同时也希望通过读这篇文章&#xff0c;你也能增加一个解决问题的经验。 相对来说&#xff0c;前端更多的是理论&#xff0c;后端更多的是需要…

Java基础:Lambda表达式方法引用

在使用Lambda表达式的时候&#xff0c;我们实际上传递进去的代码就是一种解决方案&#xff1a;拿什么参数做什么操作。那么考虑一种情况&#xff1a;如果我们在Lambda中所指定的操作方案&#xff0c;已经有地方存在相同方案&#xff0c;那是否还有必要再写重复逻辑&#xff1f;…

学习Python中turtle模块的基本用法(6:其它函数)

除了之前文章中介绍的turtle模块的绘图函数&#xff0c;本文从turtle帮助文档中梳理了其它绘图或状态函数&#xff0c;编写复杂的绘图函数时也用得到&#xff0c;函数清单如下表所示&#xff1a; 序号函数名称说明1turtle.home返回初始坐标 (0,0)&#xff0c;并设置朝向为初始…

MySQL重复与不重复问题

1.查询某个字段不重复的记录 当某个字段有重复的数据&#xff0c;而其他字段数据不一样时&#xff0c;需要查询这些不重复的记录&#xff0c;可以使用distinct关键字配合group by进行查询。 1&#xff09;先看所有的数据 2&#xff09;根据name查询不重复的记录 基本语法 s…

记一次线上fullgc----数据库查询返回大量数据

背景 某服务线上16台机器&#xff0c;晚上八点左右有4台机器突然出现fullgc&#xff0c;而且不止一次 处理流程 1&#xff09;发现机器full gc告警时&#xff0c;立即dump出机器内存快照 2&#xff09;下线问题机器 3&#xff09;分析内存快照&#xff0c;找到问题对象 可以…

JAVA中IO面试题

1.什么是IO I:Input O:Output 通过IO可以完成硬盘文件的读和写。 IO流又叫输入输出流 &#xff0c;输入和输出均是以内存作为参照物。 2. I/O流的分类? 2.1 输入流&#xff0c;输出流 以内存作为参照物&#xff0c; 往内存中去&#xff0c;叫做输入&#xff0c;或者叫做读…

【OpenFeign】【源码+图解】【六】创建FeignClient接口的代理(下)

【OpenFeign】【源码图解】【五】创建FeignClient接口的代理&#xff08;上&#xff09; 目录6.2 RequestTemplate.Factory6.3 创建SynchronousMethodHandler6.4 创建FeignInvocationHandler7. FeignInvocationHandler处理HTTP请求6.2 RequestTemplate.Factory 先看下类图 从类…

sql查询中遇到的一些小小注意点

1.sql子查询 // 最外层查询是查子查询中查询出来的结果 SELECTserverId,sum(revenue) as revenue,sum(orderCount) as orderCount,sum(refundCount) as refundCount,sum(guideRevenue) as guideRevenue,sum(cardCount) as cardCount,sum(activityCount) as activityCount,sum(…

笔试强训(7)

第一题:两种排序方法(网易)两种排序方法_牛客题霸_牛客网 题目描述:考拉有N个字符串&#xff0c;任意两个字符串的长度都不是相同的&#xff0c;考拉现在学习到了两种字符串的排序方法 1)根据字符串的字典序排序&#xff0c;比如说 "car"<"carriage"<…

CodeQL的自动化代码审计之路(下篇)

0x01 前言 CodeQL的自动化代码审计之路&#xff08;上篇&#xff09; CodeQL的自动化代码审计之路&#xff08;中篇&#xff09; 在上一篇文章中&#xff0c;我们基于CodeQL官方提供的sdk实现了自动化查询数据库功能&#xff0c;在文章中也提到实现完整的自动化代码审计还缺…