Java中异常关键字throw和throws使用方式的理解
Java中应用程序在非正常的情况下停止运行主要包含两种方式: Error 和 Exception ,像我们熟知的 OutOfMemoryError 和 IndexOutOfBoundsException 等。在日常的开发过程中 Error 我们是不用处理的,一旦 Error 发生必然证明应用程序代码上出现了问题,这个时候我们只能是修改代码。而 Exception 则是在程序运行的过程中可以进行捕获并处理的。接下来的所有讨论均会以 Exception 为主。
异常的继承图

所有的异常均继承在 Exception 类,而在其子类中又分为运行时异常RuntimeException 和 其他的异常类。所谓的运行时异常指的是在运行的时候所抛出的异常,例如:IndexOutOfBoundsException 就是 RuntimeException 的子类,访问数组下标范围外的元素,在代码的编译时期是无法被检测到的,只有在运行的时候才会抛出这样的异常。其他的异常则是 Exception 的直接子类,这些异常也可以称为编译时异常,编译时异常虽然是运行时被抛出的,但是在代码编写的过程中就会知道某些代码可能会抛出异常,并需要对其作出反应:处理或者是继续向上一层调用栈抛出。他们的主要区别可以用一句话来总结:编译时期可以发现并且需要对其作出反应的异常为编译时异常,在编译时期不能发现的异常叫运行时异常。当运行时异常发生的时候,也意味着我们是需要调整我们的代码的。在下面讨论 throws 关键字的时候会详细说明。
throw 异常的可抛性
所有的异常均可以使用 throw 关键字主动抛出,但 throw 并不能抛出一切东西,例如我们无法使用 throw 抛出一个数组或者是一个 Interger 实例。异常具有可抛性是因为 Exception 的父类是 Throwable ,只有继承它,才具有可抛性。这一点作为了解就可以了,在Java内部已经为我们定义了很多的异常,如果感觉内置的异常无法满足要求,我们也可以通过继承自`Exception 或 RuntimeExcetpion 来扩展异常。
throws 异常声明
上面我们讲过了异常的分类,包含了编译时异常和运行时异常。但是在Java中异常是需要声明的,当我们使用 throw 进行主动抛出异常时,需要在方法的后面加上 throws 关键字和异常的名字进行声明,否则代码无法正常编译。
public void getName() throws CustomException1,CustomException2 .... { //方法体 }
在这种情况下,如果别人调用我们的代码或者是我们调用其他人有类似声明的代码(例如:SimpleDateFormat 的 Parse方法)时,调用者就要对其作出反应,处理或是在调用者的方法体上继续声明,从而告诉上一层调动栈去处理,如果所有的调用栈均不处理,那么最后只能由JVM进行兜底。对于使用throws关键字进行声明的异常均为编译时异常,运行时异常在编译时无法感知,所以不需要进行异常声明。另在异常声明的时,声明的异常类型可以是抛出异常的名字或者是该异常父类的名字。
public void getName() throws Exception{
throw new CustomException1("自定义Exception异常");
}
异常的捕获
当调用异常声明的方法时,需要对其作出反应,Java提供了 try .... catch ....finally 关键字,try 中的代码块主要是用于作为异常检测,catch 用于捕获检测到的异常并处理,而 finally 则是必须执行的代码块。下面我看看一个例子
// 方法的声明
public void getName() throws CustomException { // 方法体 }
// 调用体
try { getName(); }
catch(CustomException ex){ // 处理异常 }
finally{ // 必须执行的代码 }
代码 finally 体内的代码块,不管异常能不能被捕获到,都是会执行的,通常用于做资源的释放操作。上述的代码只是一个简单捕获的例子,如果 getName 方法抛出多个异常 throws CustomException1, CusomException2 , Exception ,那又该如果捕获呢?在Java中是支持多个catch 捕获异常的,当异常的种类是同级时,多 catch 的编写顺序可以使任意的,但如果异常的声明中包含非同级时( 例如包含其父类异常 ) 编写多 catch 异常捕获的时候,需要在最后写父类捕获代码。
try { getName(); }
catch(CustomException2 ex){ // 处理异常 }
catch(CustomException1 ex){ // 处理异常 }
catch(Exception ex){ // 处理异常 }
finally{ //必须执行的代码 }
方法重写时的异常处理
由于Java的编译时异常需要进行声明,Java又是面向对象编程语言,存在继承和多态特性,随之而来的就会产生对存在这种关系的方法体异常的声明该如何定义?下面我们直接来说结论
- 当父类中对方法进行异常声明,那么子类对该方法进行覆盖时,可以进行声明也可以不进行声明,当进行声明的时候,声明的异常在继承关系上只能是该异常或者是它的子类。
- 当父类中对方法没有进行异常声明时,那么子类对该方法进行覆盖时,也不可以进行异常声明,如果子类中的方法调用了带有异常声明的方法,由于这个限制,只能在方法中进行 try....catch 处理
下面我们一起看下几个场景:
父类中的方法声明异常
public class Demo {
public static void main(String[] args) throws CustomException {
Person p = new Student();
p.GetName();
}
}
class Person{
public String GetName() throws CustomException { throw new CustomException("自定义异常"); }
}
class Student extends Person {
public String GetName() throws CustomException2 , CustomException
{
if(true) { throw new CustomException("自定义异常"); }
else { throw new CustomException2("自定义异常2"); }
}
}
class CustomException extends Exception {
public CustomException() {}
public CustomException(String message) { super(message); }
}
class CustomException2 extends CustomException {
public CustomException2() {}
public CustomException2(String message) { super(message); }
}
或
class Student extends Person {
public String GetName() { // 方法体 }
}
父类中的方法未声明异常
class Person{
public String GetName() { // 方法体 }
}
class Student extends Person {
public String GetName() {
try { // 调用带有异常声明的方法 }
catch( ... ) { // 处理异常 }
}
}
我们来理解一下为什么会有这样的限制?其根源即使多态性,编译看父类,运行是子类,当代码编译的时候,编译器解析的是父类的方法,查看的是父类的异常声明。如果子类中的异常声明高于父类或者和父类同级,试想如果父类是CustomException,子类的声明是 Exception,那么在编译的时候,编译器会提示需要处理异常 CustomException,但是在运行的时候,抛出的确是Exception,这样对于异常的捕捉就能造成很大的困扰,以至于达不到我们的预期。
总结
在本节中我们讲了Java中的异常,包含异常的分类,自定义异常,异常声明和捕捉以及在多态调用中异常的声明。在代码开发的过程中,我们应该在不同的场景中选择不同的异常使用。但是总体来看我们会使用运行时类型的异常会比较多,因为交付的软件预期内的问题我已经解决了,在软件运行的过程中产生的异常往往不在预期内,而且一旦发生就需要我们调整代码。
Java中异常关键字throw和throws使用方式的理解的更多相关文章
- Java中 try--catch-- finally、throw、throws 的用法
一.try {..} catch {..}finally {..}用法 try { 执行的代码,其中可能有异常.一旦发现异常,则立即跳到catch执行.否则不会执行catch里面的内容 } catch ...
- java中异常的抛出:throw throws
java中异常的抛出:throw throws Java中的异常抛出 语法: public class ExceptionTest{ public void 方法名(参数列表) throws 异常列表 ...
- java异常和throw和throws的区别
之前在编程中编译完成后,运行时,会遇见一些常见的错误,如NullPointerException,ArrayIndexOutOfBoundsException等等 在今天重新回顾学习了java异常,总 ...
- 浅谈java中异常抛出后代码是否会继续执行
问题 今天遇到一个问题,在下面的代码中,当抛出运行时异常后,后面的代码还会执行吗,是否需要在异常后面加上return语句呢? public void add(int index, E element) ...
- java中异常以及处理异常
一.异常简介 什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错.在java中,阻止当前方法或作用域的情况,称之为异常. java中异常的体系是怎么样的呢? 1.Java中的所有不正常类都 ...
- Java 中的关键字
Java 中有多少个关键字,有大小写之分吗? Java 中有 48 个关键字在使用 + 两个保留关键字未使用,共 50 个关键字. Java 关键字全部都由是小写组成. Java 中保留关键字分别是哪 ...
- Java中的关键字有哪些?「Java中53个关键字的意义及使用方法」
Java中的关键字有哪些? 1)48个关键字:abstract.assert.boolean.break.byte.case.catch.char.class.continue.default.do. ...
- Java中的关键字 transient
先解释下Java中的对象序列化 在讨论transient之前,有必要先搞清楚Java中序列化的含义: Java中对象的序列化指的是将对象转换成以字节序列的形式来表示,这些字节序列包含了对象的数据和信息 ...
- 《java中异常和错误》
异常和错误的区别. 异常: 在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发 ...
随机推荐
- Java基础教程:多线程杂谈——Volatile
Java基础教程:多线程杂谈——Volatile 引入Volatile Java语言提供了一种稍弱的同步机制,即Volatile变量,用来确保将变量的更新操作通知到其他线程.当把变量声明为Volati ...
- C++ 优先队列priority_queue用法【转载】
priority_queue 对于基本类型的使用方法相对简单.他的模板声明带有三个参数,priority_queue<Type, Container, Functional>Type 为数 ...
- idea设置打开文件窗口个数
idea默认是限制打开10个,超过10个后,前面打开的就会被关闭,有时候跟踪的类多了就不太友好了.
- 任务调度Quartz.Net之Windows Service
这个应该是关于Quartz.Net使用的最后一篇文章了,之前的介绍都是基于Web的,这种实现任务调度的方式很少见,因为不管是MVC.WebApi还是WebService,它们都需要寄宿在IIS上运行, ...
- java后端通过request对象获取请求的ip地址工具类
package cn.zgjkw.battalion.util; import org.apache.log4j.Logger; import javax.servlet.http.HttpServl ...
- LeetCode 605. 种花问题(Can Place Flowers) 6
605. 种花问题 605. Can Place Flowers 题目描述 假设你有一个很长的花坛,一部分地块种植了花,另一部分却没有.可是,花卉不能种植在相邻的地块上,它们会争夺水源,两者都会死去. ...
- 定时任务-SQL Server代理 作业
创建一个sqlserver作业 sqlserver的作业的功能更加偏向于数据库,处理数据,迁移等.当然也可以调用接口(存储过程调用接口 https://www.cnblogs.com/cynchan ...
- (4)Spring Boot Web开发---静态资源
文章目录 对静态资源的映射规则 模板引擎 Thymeleaf 使用 & 语法 使用之前将的快速创建项目的方法,勾选我们需要的场景,这里我需要 web --> web.sql --> ...
- php面向对象之封装
OOP三大特性:封装.继承和多态,简称封继态. 封装 类2使用关键字extends继承类1,之后,类1为类2的父类,简称父类,类2是类1的子类,简称子类.使用关键字new,实例化类1,得到对象1,对象 ...
- Python socket编程 (2)--实现文件验证登入
可以实现从客户端输入账号和密码然后发送到服务器进行验证,实现用户登入校正操作. 服务器: import socket import json server = socket.socket() serv ...