认识Java中的异常

认识Java中的异常

1. 异常的概念与体系结构

异常不同于编译错误,语法错误

算数异常:

数组下标越界异常:

空指针异常:

异常其实就是一个一个的类,所有异常都继承了Throwable类,其派生出两个重要的子类, Error 和 Exception

其中Exception又分为两大类,一类是运行时异常/非受查异常,另一类为编译时异常/受查异常。

(1)运行时异常就是代码还没运行就报错了

对于这种异常有一个很明显的特点就是要处理掉异常才能继续运行

(2)编译时异常指的是Java虚拟机无法解决的严重问题

这种情况需要程序员手动去处理错误

总结:

1. Throwable:是异常体系的顶层类,其派生出两个重要的子类, Error 和 Exception

 2. Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表: StackOverflowError和OutOfMemoryError,一旦发生回力乏术。

3. Exception:异常产生后程序员可以通过代码进行处理,使程序继续执行。比如:感冒、发烧。我们平时所说 的异常就是Exception。

2. 异常的处理

防御式编程

(1)LBYL: Look Before You Leap. 在操作之前就做充分的检查. 即:事前防御型

        缺陷:正常流程和错误处理流程代码混在一起, 代码整体显的比较混乱

(2)EAFP: It's Easier to Ask Forgiveness than Permission. "事后获取原谅比事前获取许可更容易". 也就是先操 作, 遇到问题再处理. 即:事后认错型

        优势:正常流程和错误流程是分离开的, 程序员更关注正常流程,代码更清晰,容易理解代码 异常处理的核心思想就是 EAFP。

在Java中,异常处理主要的5个关键字:throw、try、catch、final、throws。

异常的抛出

        在编写程序时,如果程序中出现错误,此时就需要将错误的信息告知给调用者,比如:参数检测。 在Java中,可以借助throw关键字,抛出一个指定的异常对象,将错误信息告知给调用者

        程序员可以通过throw来抛出异常,也可以在抛出的异常创建构造方法

      

异常的捕获

        异常的捕获,也就是异常的具体处理方式,主要有两种:异常声明throws 以及 try-catch捕获处理

        异常声明throws:处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛 给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常。

        以克隆为例:

        当加上throws CloneNotSupportedException后,声明当前方法可能会出现异常,但是这里的异常并没有被处理,只是交给了JVM处理,一旦交给JVM处理,程序就立即终止了。(即告诉JVM这里会出现异常)

【注意事项】

1. throws必须跟在方法的参数列表之后

2. 声明的异常必须是 Exception 或者 Exception 的子类

3. 方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型 具有父子关系,直接声明父类即可。

4. 调用声明抛出异常的方法时,调用者必须对该异常进行处理(需要用到try-catch),或者继续使用throws抛出。(此处以克隆为例,当方法抛出异常时,在main调用这个方法需要处理该异常,或者也抛出该异常)

try-catch捕获并处理

        throws对异常并没有真正处理,而是将异常报告给抛出异常方法的调用者,由调用者处理。如果真正要对异常进行 处理,就需要try-catch。

以克隆为例:当方法中存在异常会进入catch部分,执行catch中的语句,当不抛出异常时会继续执行,不会进入catch部分。

进一步理解

当处理完异常,想定位异常的准确位置可以通过printStackTrace()

当想处理两个不同类型的异常时,可以用多个catch()

也可以用分隔符|来进行类型的分割(但分隔符不好确定异常的种类,通常是使用多个catch())

但当有多个异常时,只会打印出一个异常。

不能任何异常都用Exception,Exception是所有异常的父类,此时从上到下过滤的

【注意事项】

1. try块内抛出异常位置之后的代码将不会被执行

2. 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到 JVM收到后中断程序----异常是按照类型来捕获的

3. try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获。如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误:

4. 可以通过一个catch捕获所有的异常,即多个异常,一次捕获(不推荐)

由于 Exception 类是所有异常类的父类. 因此可以用这个类型表示捕捉所有异常.

finally

        finally用于资源的释放,是否出现异常finally都可以实现断后操作。close()可以写入finally当中(try后面也可以跟小括号,可实现输入)

注意:finally中的代码一定会执行的,一般在finally中进行一些资源清理的扫尾工作

关于finally的执行是最后,需要特殊记一下(理论上返回的值是10,但不是立刻返回的,底层将其修改为20)

一般我们不建议在 finally 中写 return (被编译器当做一个警告)

异常的处理流程

        处理异常的顺序:从方法本身来处理异常,到谁调用此方法谁处理异常,最后交给JVM来处理异常

如果向上一直传递都没有合适的方法处理异常, 最终就会交给 JVM 处理, 程序就会异常终止(和我们最开始未使用 try catch 时是一样的)

【异常处理流程总结】

程序先执行 try 中的代码

如果 try 中的代码出现异常, 就会结束 try 中的代码, 看和 catch 中的异常类型是否匹配.

如果找到匹配的异常类型, 就会执行 catch 中的代码

如果没有找到匹配的异常类型, 就会将异常向上传递到上层调用者.

无论是否找到匹配的异常类型, finally 中的代码都会被执行到(在该方法结束之前执行).

如果上层调用者也没有处理的了异常, 就继续向上传递.

一直到 main 方法也没有合适的代码处理异常, 就会交给 JVM 来进行处理, 此时程序就会异常终止.

3.throw 和 throws 的区别

throw是扔出一个程序,而throws是在方法声明的地方声明一个异常

4. 自定义异常类

Java 中虽然已经内置了丰富的异常类, 但是并不能完全表示实际开发中所遇到的一些异常,此时就需要维护符合我 们实际情况的异常结构.

以用户登录为例

此时我们想自定义用户账户和密码异常,可以定义一个异常类继承​​​​​​​RuntimeException,并且重写

两个构造方法

继承RuntimeException和Exception的不同

继承RuntimeException,异常为编译时异常或者受查异常。

继承Exception,异常为运行时异常或者非受查异常。

解决方法如下

(1)自己用try和catch处理异常,同时注意不要再去main中去解决异常

(2)声明异常

注意事项

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

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

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

Read more

GESP-C++考试(二级)考试重点 (附:【编程题模板】大全)

GESP-C++考试(二级)考试重点 (附:【编程题模板】大全)

一、GESP C++ 二级考试重点 “会写多层 if else  +  多层循环  +  用基础数学函数解决综合问题” (一)理论部分重点(选择 / 判断题高频) 根据大纲,以下内容是必考且高频 GESP大纲: (1)计算机基础 * 存储器 * RAM(内存) vs ROM(只读) * Cache(高速缓存) * 网络 * LAN / MAN / WAN * OSI 七层模型(知道名字) * TCP/IP 四层模型(知道名字) * 程序设计语言 * 机器语言 / 汇编语言 / 高级语言 * C++ 属于高级语言 👉 特点: * 不考计算 * 多为“认识型”“判断型” (2)流程图

By Ne0inhk
《C++ 基础进阶:内存开辟规则、类型转换原理与 IO 流高效使用》

《C++ 基础进阶:内存开辟规则、类型转换原理与 IO 流高效使用》

前引:在 C++ 编程中,内存管理是程序稳定性与性能的基石,而类型转换与 IO 流则是数据处理和交互的核心工具。栈与堆作为内存分配的两大核心区域,其开辟方式直接决定了变量的生命周期、访问效率及内存安全 —— 错误的分配策略可能导致内存泄漏、野指针或栈溢出等致命问题。与此同时,类型转换的合理性关乎类型系统的严谨性,不当转换易引发数据截断、逻辑错误;IO 流作为数据输入输出的桥梁,其正确使用则直接影响程序与外部设备(如控制台、文件)交互的可靠性! 目录 【一】内存完美开辟 (1)栈和堆的本质区别 (2)如何只在栈上开辟空间 (3)如何只在堆上开辟空间 【二】C++的四种类型转换 (1)static_cast (2)reinterpret_cast (3)const_cast (4)dynamic_cast 【三】operator类型转换 (1)

By Ne0inhk
华为OD机试双机位C卷:采购订单 (Py/Java/C/C++/Js/Go)

华为OD机试双机位C卷:采购订单 (Py/Java/C/C++/Js/Go)

采购订单 华为OD机试双机位C卷 - 华为OD上机考试双机位C卷 100分题型 华为OD机试双机位c卷真题目录点击查看: 华为OD机试双机位C卷真题题库目录|机考题库 + 算法考点详解 题目描述 在一个采购系统中,采购申请(PR)需要经过审批后才能生成采购订单(PO)。每个PR包含商品的单价(假设相同商品的单价一定是一样的)及数量信息。系统要求对商品进行分类处理:单价高于100元的商品需要单独处理,单价低于或等于100元的相同商品可以合并到同一采购订单PO中。针对单价低于100的小额订单,如果量大可以打折购买。 具体规则如下: 如果PR状态为"审批通过",则将其商品加入到PO中。如果PR的状态为"审批拒绝"或"待审批",则忽略改PR。 对于单价高于100元的商品,每个商品单独生成一条PO记录。对于单价低于100元的商品,将相同商品的数量合并到一条PO记录中。 如果商品单价<100且商品数量>=100,则单价打9折。 输入描述 第一行包含整数N,

By Ne0inhk