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又是面向对象编程语言,存在继承和多态特性,随之而来的就会产生对存在这种关系的方法体异常的声明该如何定义?下面我们直接来说结论

  1. 当父类中对方法进行异常声明,那么子类对该方法进行覆盖时,可以进行声明也可以不进行声明,当进行声明的时候,声明的异常在继承关系上只能是该异常或者是它的子类。
  2. 当父类中对方法没有进行异常声明时,那么子类对该方法进行覆盖时,也不可以进行异常声明,如果子类中的方法调用了带有异常声明的方法,由于这个限制,只能在方法中进行 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使用方式的理解的更多相关文章

  1. Java中 try--catch-- finally、throw、throws 的用法

    一.try {..} catch {..}finally {..}用法 try { 执行的代码,其中可能有异常.一旦发现异常,则立即跳到catch执行.否则不会执行catch里面的内容 } catch ...

  2. java中异常的抛出:throw throws

    java中异常的抛出:throw throws Java中的异常抛出 语法: public class ExceptionTest{ public void 方法名(参数列表) throws 异常列表 ...

  3. java异常和throw和throws的区别

    之前在编程中编译完成后,运行时,会遇见一些常见的错误,如NullPointerException,ArrayIndexOutOfBoundsException等等 在今天重新回顾学习了java异常,总 ...

  4. 浅谈java中异常抛出后代码是否会继续执行

    问题 今天遇到一个问题,在下面的代码中,当抛出运行时异常后,后面的代码还会执行吗,是否需要在异常后面加上return语句呢? public void add(int index, E element) ...

  5. java中异常以及处理异常

    一.异常简介 什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错.在java中,阻止当前方法或作用域的情况,称之为异常. java中异常的体系是怎么样的呢? 1.Java中的所有不正常类都 ...

  6. Java 中的关键字

    Java 中有多少个关键字,有大小写之分吗? Java 中有 48 个关键字在使用 + 两个保留关键字未使用,共 50 个关键字. Java 关键字全部都由是小写组成. Java 中保留关键字分别是哪 ...

  7. Java中的关键字有哪些?「Java中53个关键字的意义及使用方法」

    Java中的关键字有哪些? 1)48个关键字:abstract.assert.boolean.break.byte.case.catch.char.class.continue.default.do. ...

  8. Java中的关键字 transient

    先解释下Java中的对象序列化 在讨论transient之前,有必要先搞清楚Java中序列化的含义: Java中对象的序列化指的是将对象转换成以字节序列的形式来表示,这些字节序列包含了对象的数据和信息 ...

  9. 《java中异常和错误》

    异常和错误的区别. 异常: 在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发 ...

随机推荐

  1. scons 简单入门

    scons 简单入门 摘自:https://www.jianshu.com/p/e4bd3ab9e5d6 0.2042019.01.20 12:58:44字数 1201阅读 3021 简单入门 hel ...

  2. C++构造函数以及何时被调用

    using namespace std; class A { public: A() { cout << "默认无参构造函数" << endl; } #if ...

  3. 聚类K-Means和大数据集的Mini Batch K-Means算法

    import numpy as np from sklearn.datasets import make_blobs from sklearn.cluster import KMeans from s ...

  4. Django中的ModelForm与Form

    django表单系统中,所有的表单类都作为django.forms.Form的子类创建,包括ModelForm. 关于django中的表单系统有两种: 基于django.forms.Form 基于dj ...

  5. LeetCode_234. Palindrome Linked List

    234. Palindrome Linked List Easy Given a singly linked list, determine if it is a palindrome. Exampl ...

  6. Go micro 开发微服务步骤

    1.写 proto文件,定义接口和服务 2.实现 接口,注册 handle 3.调用服务:直接用rpc 客户端调用,或者用 api http web等调用 api http web 等服务可以对客户端 ...

  7. 《MySQL必知必会》学习笔记——第30章 改善性能

    本章将付息与MySQL性能有关的某些要点. 30.1 改善性能 数据库管理员把他们生命中的相当一部分时间花在了调整.试验以改善DBMS性能之上.在诊断英勇的滞缓现象和性能问题时,性能不良的数据库(以及 ...

  8. Docker入门之docker-compose

    参考:https://blog.51cto.com/9291927/2310444 一,Docker-compose简介 1,Docker-compose简介 Docker-Compose项目是Doc ...

  9. Cas(09)——通过Proxy访问其它Cas应用

    通过Proxy访问其它Cas应用 目录 1.1     原理 1.2     配置 1.2.1    代理端 1.2.2    被代理端 1.3     请求示例 考虑这样一种场景:有两个应用App1 ...

  10. 最新 迅游科技java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.迅游科技等10家互联网公司的校招Offer,因为某些自身原因最终选择了迅游科技.6.7月主要是做系统复习.项目复盘.Leet ...