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让你知道,你(开发 ...
随机推荐
- 报错:Unable to read additional data from client sessionid 0x36ab52d38c20b20, likely client has closed socket
报错背景: CDH集群中,将kafka和Flume整合,将kafka的数据发送给Flume消费. 启动kafka的时候正常,但是启动Flume的时候出现了报错现象. 但是我检查了Flume,Flume ...
- Sql server with as update用法
create table t1 ( id int,[names] varchar(100)) create table t2( id int,[names] varchar(100)) insert ...
- Python - Django - 封装分页成通用的模块
新建 utils 文件夹,并创建 page.py page.py: class ShowPage(object): def __init__(self, page_num, total_count, ...
- 如何修改WAMPServer默认的网站路径地址
通常,我们安装WAMPServer集成的PHP开发环境之后,默认的网站路径地址是其安装目录下子文件夹:"wamp/www/".那么我们怎么修改网站地址到自己指定的路径呢?本篇经验将 ...
- CF1277D Let's Play the Words?
思路: 字符串其实只有0...0, 0...1, 1...0, 1...1四种. 实现: #include <bits/stdc++.h> using namespace std; ]; ...
- JS 多数组中取最大数组,分组
代码小结,使用 JS 对数据进行分组,对分组中的数组取最大数组: var combineTemplate = JSON.parse(data.combineTemplate); //根据仪器种类ID分 ...
- SCI-hub使用技巧(下载外文文献)
下载外文文献方法指南: (1)首先查找需要下载文献的DOI (2)在Sci-Hub主页搜索框输入URL.DOI或者PMID. (3)点击open即可看见下载界面. 参考文献:https://mp.we ...
- 017 Android 获取手机SIM卡序列号和读取联系人
1.获取手机SIM卡序列号 //5.存储sim卡系列号 //5.1获取sim卡系列号 TelephonyManager manager = (TelephonyManager) getSystemSe ...
- 'telent' 不是内部或外部命令,也不是可运行的程序或批处理文件。
今天在Windows 7操作系统中安装了memcached内存缓存软件,本想借助Windows的telnet程序向memcached缓存管理系统中添加一些数据,可是命令输入后竟然出现了如下图这样的错误 ...
- 小贴士--java篇
1. java: “.”和“|”都是转义字符,必须得加"\\" 2.java :如果在一个字符串中有多个分隔符,可以用“|”作为连字符,比如:“acount=? and uu = ...