Java基础-异常(Exception)处理

                                      作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.异常的概述

  什么是异常?Java代码在运行时期发生的问题就是异常。在Java中,把异常信息封装成了一个类。当出现了问题时,就会创建异常类对象,并抛出异常相关信息(如异常信息出现的位置,原因等)。

二.异常的继承体系

  在Java中使用Exception类来描述异常。Exception类及其子类是Throwable的一种形式,它指出了合理应用程序想要捕获的异常条件。查看Java的API文档我们可以发现Exception有继承关系,它的父类是Throwable。Throwable是Java语言中所有错误或异常的超类。另外,在异常Exception类中,有一个子类要特殊说明一下,RuntimeException子类,RuntimeException及其它的子类只能在Java程序运行过程中出现。

  我们再来观察Throwable类,能够发现与异常Exception平级的有一个Error,它是Throwable的子类,它用来表示Java程序中可能会产生的严重错误。解决办法只有一个,修改代码避免Error错误的产生。下面是一个Error异常的案例:

  综上所述,异常继承体系可以大致做以下简要分类,此处并未列出全部的异常,请以Java的API文档为标准,下图只是为了方便记忆:

三.异常对象的产生原因和处理方式

  我们看见上面的代码是有异常抛出的,那么异常究竟是怎么抛出的呢?其实他大致分为以下几个步骤:

1>.JVM检测到异常

  通过上面的学习,我们知道异常的祖宗其实就是Throwable类,在这个类下面很多个子类已经提前定义好了。在代码运行的时候,JVM是完全有能力检测到出现的异常信息(比如:ArrayIndexOutOfBoundsException)。

2>.JVM创建异常对象

  当JVM虚拟机检测到异常后,首先会创建异常对象(比如:new  java.lang.ArrayIndexOutOfBoundsException: 5)。

3>.将异常抛给方的调用者

  当创建好异常后,首先JVM虚拟机会检测程序手否对这种类型的异常有相应的处理方式,如果有,则按照业务逻辑执行,如果没有,就会将异常的对象进行抛出,最终会抛给方法的调用者。

4>.调用者继续抛出异常

  从上面的代码中可以看到,getAway方法的调用者是main函数,因此会把异常抛给main方法,JVM虚拟机又会在main方法查找是否有异常处理的方式,如果没有对数组越界异常进行处理就将异常对象(java.lang.ArrayIndexOutOfBoundsException: 5)继续向上抛出,也就是main方法的调用者。而main方法运行在栈内存中,实际上是抛给了JVM虚拟机啦。

5>.JVM虚拟机收到异常后的事情

  其实JVM虚拟机(最终异常的处理者)收到异常后,做了两件事情:

    a>.将异常信息的内容输出,让程序员进行排错;

    b>.杀死抛出异常的进程(也就是结束main方法);

四.方法内部抛出对象关键字(throw

  在编写程序时,我们必须要考虑程序出现问题的情况。比如,在定义方法时,方法需要接受参数。那么,当调用方法使用接受到的参数时,首选需要先对参数数据进行合法判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。在Java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
public static void main(String[] args){
int[] arr = null;
// int[] arr1 = {};
int i = getArray(arr);
System.out.println(i);
} //对数组的最后索引*2,返回
public static int getArray(int[] arr){
//对方法参数进行合法性的判断,进行判断是不是null
if(arr == null){
//通过关键字throw抛出异常的形式,告诉调用者。
throw new RuntimeException("传递的数组不存在");
} //对数组进行判断,判断数组中是否储存在元素。
if(arr.length == 0){
//以抛出异常的形式,告诉调用者,数组中没有元素
throw new RuntimeException("传递的是空数组");
}else{
int i = arr[arr.length-1];
return i*2;
}
}
} /*
以上代码执行结果如下:
Exception in thread "main" java.lang.RuntimeException: 传递的数组不存在
at ExceptionDemo.getArray(ExceptionDemo.java:20)
at ExceptionDemo.main(ExceptionDemo.java:11)
*/

五.异常方法声明关键字(throws)

  throws用于在方法的声明上,标明此方法可能出现异常的类型,让调用者自己处理。换句话说,调用了一个抛出异常的方法,调用者就必须处理,若不处理,就会编译失败。

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
//main方法将异常抛给了JVM虚拟机。
public static void main(String[] args) throws Exception{
// int[] arr1 = null;
int[] arr2 = {};
int i = getArray(arr2);
System.out.println(i);
} //对数组的最后索引*2,通过throws关键字声明抛出的异常,调用者必须处理,否则编译失败!
public static int getArray(int[] arr) throws Exception{
//对方法参数进行合法性的判断,进行判断是不是null
if(arr == null){
//通过关键字throw抛出异常的形式,告诉调用者。
throw new Exception("传递的数组不存在");
} //对数组进行判断,判断数组中是否储存在元素。
if(arr.length == 0){
//以抛出异常的形式,告诉调用者,数组中没有元素
throw new Exception("传递的是空数组");
}else{
int i = arr[arr.length-1];
return i*2;
}
}
} /*
以上代码执行结果如下:
Exception in thread "main" java.lang.Exception: 传递的是空数组
at ExceptionDemo.getArray(ExceptionDemo.java:28)
at ExceptionDemo.main(ExceptionDemo.java:12)
*/

六.Java中的异常处理方式

1>.异常处理格式

 try{
被检测的代码;
可能出现异常的代码;
}catch(异常类名变量){
异常的处理方式;
循环,判断,调用方法,变量
}finally{
必须要执行的代码;
}

2>.try...异常处理

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
//main方法进行处理异常
public static void main(String[] args){
int[] arr = null;
try{
int i = getArray(arr);
System.out.println(i);
}catch(NullPointerException e) {
System.out.println(e);
}
System.out.println("Game Over!");
} //创建异常对象并抛出
public static int getArray(int[] arr) throws NullPointerException{
//对方法参数进行合法性的判断,进行判断是不是null
if(arr == null){
//手动抛出异常,抛出空指针异常
throw new NullPointerException("传递的数组不存在");
} //对数组的索引进行判断
if(arr.length < 3){
//手动抛出异常,抛出数组的索引越界异常
throw new ArrayIndexOutOfBoundsException("数组没有下标为3的索引");
}
return arr[3]+1;
}
} /*
以上代码执行结果如下:
java.lang.NullPointerException: 传递的数组不存在
Game Over! */

ExceptionDemo.java 文件内容

3>.异常多catch处理

  平级异常,抛出的异常类之间,没有继承关系。上下级关系的异常,越高级的父类越应该写在下面。

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
//main方法进行处理异常
public static void main(String[] args){
int[] arr = new int[0];
try{
int i = getArray(arr);
System.out.println(i);
}catch(NullPointerException e) {
System.out.println(e);
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println(e);
}catch(Exception e){ //Exception应该放在最后一个catch,因为它包含上面2种异常。
System.out.println(e);
}
System.out.println("Game Over!");
} //可以抛出多个异常
public static int getArray(int[] arr) throws NullPointerException,ArrayIndexOutOfBoundsException{
//对方法参数进行合法性的判断,进行判断是不是null
if(arr == null){
//手动抛出异常,抛出空指针异常
throw new NullPointerException("传递的数组不存在");
} //对数组的索引进行判断
if(arr.length < 3){
//手动抛出异常,抛出数组的索引越界异常
throw new ArrayIndexOutOfBoundsException("数组没有下标为3的索引");
}
return arr[3]+1;
}
} /*
以上代码执行结果如下:
java.lang.ArrayIndexOutOfBoundsException: 数组没有下标为3的索引
Game Over!
*/

4>.finnal代码块

  finally中的代码块无论程序是否有异常,程序都必须执行里面的代码(除非你在来到finally之前就用System.exit(0)退出程序啦!)。它一般用来释放IO资源,比如关闭文件或者关闭数据库的链接等等。

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
//main方法进行处理异常
public static void main(String[] args){
int[] arr = new int[0];
try {
function(100);
}catch(Exception e){
System.out.println(e);
}finally {
System.out.println("必须要执行的代码!");
}
System.out.println("Game Over!");
} //创建异常对象并抛出
public static void function(int a) throws Exception{
if(a == 0) {
throw new Exception();
}else {
System.out.println(a);
}
}
} /*
以上代码执行结果如下:
100
必须要执行的代码!
Game Over!
*/

5>.运行时期异常的特点

  异常分为编译异常和运行时异常。

a>.编译异常

  调用了抛出异常的方法(抛出编译异常需要在方法上用关键字throws声明异常),不处理的话就会编译不通过。处理方式有两种,第一种就是用try语句进行处理,或者是用throws语句丢给调用者去处理。

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
//main方法进行处理异常
public static void main(String[] args){
int[] arr = new int[0];
try {
function(100);
}catch(Exception e){
System.out.println(e);
}finally {
System.out.println("必须要执行的代码!");
}
System.out.println("Game Over!");
} //抛出编译异常需要在方法上用关键字throws声明异常
public static void function(int a) throws Exception{
//创建编译异常
throw new Exception();
}
} /*
以上代码执行结果如下:
java.lang.Exception
必须要执行的代码!
Game Over! */

编译异常(Exception)案例展示

b>.运行时期异常

  抛出的异常是RuntimeException类,或者是他的子类。方法内部抛出的异常是运行异常,在方法声明上,不需要throws语句。不仅如此,运行时异常我们也不需要去用try语句或者throws语句去处理。

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
//main方法进行处理异常
public static void main(String[] args){
//调用者,不需要处理异常
function(100);
}
//运行时异常可以不用在方法上用关键字throws声明。
public static void function(int a){
//创建运行时异常
throw new RuntimeException();
}
}

运行时异常(RuntimeException)案例展示

c>.运行异常的设计原因

  运行异常,在编译的时候不能察觉出来,如果发生了运行异常,程序人员停止程序修改源代码。运行异常一旦发生,后面的代码没有执行的意义。比如我们看下面一段代码,估计身为老司机的你一眼就看出问题了,但是在编译的时候就不死活不报错,一旦你运行就会崩溃。

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
public static void main(String[] args){
int[] arr = {1,2,3};
function(arr);
} public static void function(int[] arr){
/* 此处我们对数组的第六个元素进行操作,但是如果传入的数组长度不到6,
*则继续向下执行代码就没有任何意义,程序员应该修改以下的代码逻辑性!
*/
if(arr[5] > 100) {
arr[5] = arr[5]/10;
}else {
arr[5] = arr[5]/3;
}
}
}

d>.运行异常的案例

  定义一个方法,计算一个圆形面积。传递参数为负数时可以完成计算,但是违反了真实情况,因此我们可以将传入的数据进行判断,如果不符合现实情况就让程序崩溃掉,让调用者传入合法的数据信息,我们举一个简单的案例(求圆形的面积,你可以补充求周长来练习):

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
public static void main(String[] args){
//传入一个负数去求面积,会导致程序崩溃
double d = getArea(-1);
System.out.printf("圆形的面积是:%f\n",d);
} //定义方法,计算圆形的面积
public static double getArea(double r){
//当传入的半径是非正数时,就让程序崩溃掉!
if(r <= 0) {
throw new RuntimeException("圆形不存在");
}
return r*r*Math.PI; }
} /*
以上代码执行结果如下:
Exception in thread "main" java.lang.RuntimeException: 圆形不存在
at ExceptionDemo.getArea(ExceptionDemo.java:19)
at ExceptionDemo.main(ExceptionDemo.java:11) */

6>.方法重写时候异常的处理

  继承后,在子类重写父类方法的时候,异常处理结论:

    a>.父类的方法如果抛出异常,子类重写后可以不抛出异常,也可以不抛出异常,但是,如果子类要抛,抛出的异常不能大于父类的异常(都指的是继承关系);

    b>.父类的方法没有异常抛出,子类重写后也不能抛出异常;

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
public static void main(String[] args){ }
} class Father{
public void function()throws Exception{ }
} class Son extends Father{
//子类可以抛出异常也可以不抛出异常Exception
public void function(){ }
}

父类抛出异常,子类可以不抛出异常

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
public static void main(String[] args){ }
} class Father{
public void function(){ }
} class Son extends Father{
//子类可以抛出异常也可以不抛出异常Exception
public void function(){ }
}

父类不抛出异常,子类就不能抛出异常

七.自定义异常

1>.Throwable类常用的方法

  a>.String getMessage()    :对异常信息的详细描述。
  b>.String toString()      :对异常信息的简短描述。
  c>.void printStackTrace()   :将异常信息追踪到标准的错误流,也是JVM虚拟机默认调用的方式,因为它的异常信息最详细。

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ public class ExceptionDemo{
public static void main(String[] args){
try {
function();
}catch(Exception e) {
System.out.println(e.getMessage());
System.out.println(e.toString());
e.printStackTrace(); //JVM默认调用的就是这个方法,异常信息最全。
} } public static void function() throws Exception{
throw new Exception("异常啦!");
} } /*
以上代码执行结果如下:
异常啦!
java.lang.Exception: 异常啦!
java.lang.Exception: 异常啦!
at ExceptionDemo.function(ExceptionDemo.java:22)
at ExceptionDemo.main(ExceptionDemo.java:11)
*/

2>.自定义异常

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
EMAIL:y1053419035@qq.com
*/ //自定义异常类
class MyException extends RuntimeException{ MyException(String message){
super(message);
}
} public class ExceptionDemo{
public static void main(String[] args){
try{
test();
}catch(MyException e){
System.out.println(e.getMessage());
//....
}
} public static void test() throws MyException {
throw new MyException("发生自定义异常!");
}
} /*
以上代码执行结果如下:
发生自定义异常!
*/

Java基础-异常(Exception)处理的更多相关文章

  1. 《Java基础——异常的捕获与抛出》

    Java基础--异常的捕获与抛出     '  前言: Error类(错误)和Exception类(异常)是Throwable类的子类. 异常分为CheckedException类(编译时异常)和Ru ...

  2. Atitit java的异常exception 结构Throwable类

    Atitit java的异常exception 结构Throwable类 1.1. Throwable类 2.StackTrace栈轨迹1 1.2. 3.cause因由1 1.3. 4.Suppres ...

  3. Java基础 - 异常详解

    异常的层次结构 Throwable Throwable 是 Java 语言中所有错误与异常的超类. Throwable 包含两个子类:Error(错误)和 Exception(异常),它们通常用于指示 ...

  4. Java基础(55):Exception类详解(转)

    Java中的异常 Exception java.lang.Exception类是Java中所有异常的直接或间接父类.即Exception类是所有异常的根类. 比如程序: public class Ex ...

  5. Java基础——异常体系

    在Java中,异常对象都是派生于Throwable类的一个实例,Java的异常体系如下图所示: 所有的异常都是由Throwable继承而来,在下一层立即分解为两个分支,Error和Exception. ...

  6. JAVA基础——异常详解

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

  7. Java常见异常:Exception in thread "main" java.lang.NoClassDefFoundError

    在某一路径下执行编译好的class文件出错. 异常如下: E:\liwy>java Test98 Exception in thread "main" java.lang.N ...

  8. Java基础——异常

    一.什么是异常  异常的英文单词是exception,字面翻译就是“意外.例外”的意思,也就是非正常情况.事实上,异常本质上是程序上的错误,包括程序逻辑错误和系统错误.比如使用空的引用.数组下标越界. ...

  9. Java基础——异常机制

    [捕获异常] 硬件的错误.输入错误.物理限制等问题,都可能导致程序运行时的异常出现. 1.异常的分类层次 在java中,异常对象都是由Throwable类继承而来的,主要分为两大类: Error和Ex ...

随机推荐

  1. Task 6.3 场景调研

    1.背景: (1)典型用户:信息1303班王银凤 (2)用户的需求/迫切需要解决的问题:她们宿舍上网一直使用的是外网,一年400的一种“套餐”.这种是按小时计算的,在校的时间平均下来一天可以用7 . ...

  2. IT职业道路的苦与甜

    每当有人问起你学的是什么专业啊?学的怎么样啊?好不好学啊?等等一些类似的问题.我都会默默的说一句,会者不难,难者不会.当然现在的我还处于菜鸟级别,不过我相信在不久后的一天我一定会脱离菜鸟的行列,然后挺 ...

  3. 结对项目-四则运算出题程序(GUI版)

    目录: 一.致搭档(含项目地址) 二.PSP(planning) 三.结对编程中对接口的设计 四.计算模块接口的设计与实现过程 五.计算模块接口部分的性能改进 六.计算模块部分单元测试展示 七.计算模 ...

  4. raise PDFEncryptionError('Unknown algorithm: param=%r' % param) pdfminer.pdfdocument.PDFEncryptionError: Unknown algorithm

    使用pdfminer遇到的pdf文件加密问题: raise PDFEncryptionError('Unknown algorithm: param=%r' % param) pdfminer.pdf ...

  5. Java面试& HashMap实现原理分析

    1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端.  数组 数组存储区间是连续的,占用内存严重,故空间复杂的很大.但数组的二分查找时间复杂度小,为O( ...

  6. C/C++ 打印文件名、行号、函数名的方法

    转自:http://zhidao.baidu.com/link?url=JLCaxBAXLJVcx_8jsyJVF92E_bZjo4ONJ5Ab-HGlNBc1dfzcAyFAIygwP1qr18aa ...

  7. 用go实现的一个堆得数据结构

    用golang实现的堆,主要提供了两个方法,push和pop及堆的大小,代码如下: package main import ( "errors" "fmt" ) ...

  8. [转帖]紧急预警:Globelmposter3.0变种来袭,多行业中招

    紧急预警:Globelmposter3.0变种来袭,多行业中招 https://www.csdn.net/article/a/2018-09-04/15959658   CSDN 转载深信服...   ...

  9. Tomcat 启动流程

  10. Java的StringBuIlder扩容机制

    JDK 1.6中,扩容的源码是这样: void expandCapacity(int minimumCapacity) { int newCapacity = (value.length + 1) * ...