深入探讨Java语言中的异常与错误处理
龚超 2018-07-26 来源 : 阅读 283 评论 0

摘要:本文主要向大家介绍了Java语言中的异常与错误处理,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了Java语言中的异常与错误处理,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

Java中的异常处理机制已经比较成熟,我们的java程序到处充满了异常的可能,如果对这些异常不做预先的处理,那么将来程序崩溃就无从调试,很难找到异常所在的位置。本文将探讨一下Java中异常与错误的处理方法,一起来看看。

异常与错误:

异常:

在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发人员)已经犯了个错误,现在有一个机会来修改它。Java中使用异常类来表示异常,不同的异常类代表了不同的异常。但是在Java中所有的异常都有一个基类,叫做Exception。

错误:

它指的是一个合理的应用程序不能截获的严重的问题。大多数都是反常的情况。错误是VM的一个故障(虽然它可以是任何系统级的服务)。所以,错误是很难处理的,一般的开发人员(当然不是你)是无法处理这些错误的,比如内存溢出。 和异常一样,在Java中用错误类来表示错误,不同的错误类代表了不同的错误。 但是在Java中所有的错误都有一个基类,叫做Error。

综上,我们可以知道异常和错误最本质的区别就是异常能被开发人员处理而错误时系统本来自带的,一般无法处理也不需要我们 程序员 来处理。

1.一个异常是在一个程序执行过程中出现的一个事件,它中断了正常指令的运行

2.错误,偏离了可接受的代码行为的一个动作或实例

异常的结构分类:

1、运行时异常(未检查异常)

2、编译时异常(已检查异常)

运行异常即是RuntimeException;其余的全部为编译异常

在Java中异常Exception和错误Error有个共同的父类Throwable。

Error Exception

runtimeException几个子类

1、 java.lang.ArrayIndexOutOfBoundsException

数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。

2、java.lang.ArithmeticException

算术条件异常。譬如:整数除零等。

3、java.lang.NullPointerException

空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的

属性、计算null对象的长度、使用throw语句抛出null等等

4、java.lang.ClassNotFoundException

找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出

该异常。

对异常的处理:

try{}catch{}

try{}catch{}finally{}无论有无异常finally代码块都会被执行

try{}finally{}也是可以组合使用的但是catch{}finally{}不可以

注意:在继承关系中,子类覆盖父类的方法,抛出异常的范围不能比父类更宽泛

异常的使用

在异常的使用这一部分主要是演示代码,都是我们平常写代码的过程中会遇到的(当然只是一小部分),抛砖引玉吗!

例1. 这个例子主要通过两个方法对比来演示一下有了异常以后代码的执行流程。


public static void testException1() {

int[] ints = new int[] { 1, 2, 3, 4 };

System.out.println("异常出现前");

try {

System.out.println(ints[4]);

System.out.println("我还有幸执行到吗");// 发生异常以后,后面的代码不能被执行

} catch (IndexOutOfBoundsException e) {

System.out.println("数组越界错误");

}

System.out.println("异常出现后");

}

复制代码

/*output:

异常出现前

数组越界错误

常出现后

*/


public static void testException2() {

int[] ints = new int[] { 1, 2, 3, 4 };

System.out.println("异常出现前");

System.out.println(ints[4]);

System.out.println("我还有幸执行到吗");// 发生异常以后,他后面的代码不能被执行

}

复制代码

首先指出例子中的不足之处,IndexOutofBoundsException是一个非受检异常,所以不用try…catch…显示捕捉,但是我的目的是对同一个异常用不同的处理方式,看它会有什么不同的而结果(这里也就只能用它将就一下了)。异常出现时第一个方法只是跳出了try块,但是它后面的代码会照样执行的。但是第二种就不一样了直接跳出了方法,比较强硬。从第一个方法中我们看到,try…catch…是一种”事务性”的保障,它的目的是保证程序在异常的情况下运行完毕,同时它还会告知程序员程序中出错的详细信息(这种详细信息有时要依赖于程序员设计)。

例2. 重新抛出异常


public class Rethrow {

public static void readFile(String file) throws FileNotFoundException {

try {

BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));

} catch (FileNotFoundException e) {

e.printStackTrace();

System.err.println("不知道如何处理该异常或者根本不想处理它,但是不做处理又不合适,这是重新抛出异常交给上一级处理");

//重新抛出异常

throw e;

}

}

public static void printFile(String file) {

try {

readFile(file);

} catch (FileNotFoundException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

printFile("D:/file");

}

}

复制代码

异常的本意是好的,让我们试图修复程序,但是现实中我们修复的几率很小,我们很多时候就是用它来记录出错的信息。如果你厌倦了不停的处理异常,重新抛出异常对你来说可能是一个很好的解脱。原封不动的把这个异常抛给上一级,抛给调用这个方法的人,让他来费脑筋吧。这样看来,java异常(当然指的是受检异常)又给我们平添很多麻烦,尽管它的出发点是好的。

例3. 异常链的使用及异常丢失


ExceptionA,ExceptionB,ExceptionC

public class ExceptionA extends Exception {

public ExceptionA(String str) {

super();

}

}

public class ExceptionB extends ExceptionA {

public ExceptionB(String str) {

super(str);

}

}

public class ExceptionC extends ExceptionA {

public ExceptionC(String str) {

super(str);

}

}

复制代码

异常丢失的情况:


public class NeverCaught {

static void f() throws ExceptionB{

throw new ExceptionB("exception b");

}

static void g() throws ExceptionC {

try {

f();

} catch (ExceptionB e) {

ExceptionC c = new ExceptionC("exception a");

throw c;

}

}

public static void main(String[] args) {

try {

g();

} catch (ExceptionC e) {

e.printStackTrace();

}

}

}

/*

exception.ExceptionC

at exception.NeverCaught.g(NeverCaught.java:12)

at exception.NeverCaught.main(NeverCaught.java:19)

*/

复制代码

为什么只是打印出来了ExceptionC而没有打印出ExceptionB呢?这个还是自己分析一下吧!

上面的情况相当于少了一种异常,这在我们排错的过程中非常的不利。那我们遇到上面的情况应该怎么办呢?这就是异常链的用武之地:保存异常信息,在抛出另外一个异常的同时不丢失原来的异常。


public class NeverCaught {

static void f() throws ExceptionB{

throw new ExceptionB("exception b");

}

static void g() throws ExceptionC {

try {

f();

} catch (ExceptionB e) {

ExceptionC c = new ExceptionC("exception a");

//异常连

c.initCause(e);

throw c;

}

}

public static void main(String[] args) {

try {

g();

} catch (ExceptionC e) {

e.printStackTrace();

}

}

}

/*

exception.ExceptionC

at exception.NeverCaught.g(NeverCaught.java:12)

at exception.NeverCaught.main(NeverCaught.java:21)

Caused by: exception.ExceptionB

at exception.NeverCaught.f(NeverCaught.java:5)

at exception.NeverCaught.g(NeverCaught.java:10)

... 1 more

*/

复制代码

这个异常链的特性是所有异常均具备的,因为这个initCause()方法是从Throwable继承的。

例4. 清理工作

清理工作对于我们来说是必不可少的,因为如果一些消耗资源的操作,比如IO,JDBC。如果我们用完以后没有及时正确的关闭,那后果会很严重,这意味着内存泄露。异常的出现要求我们必须设计一种机制不论什么情况下,资源都能及时正确的清理。这就是finally。


public void readFile(String file) {

BufferedReader reader = null;

try {

reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));

// do some other work

} catch (FileNotFoundException e) {

e.printStackTrace();

} finally {

try {

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

复制代码

例子非常的简单,是一个读取文件的例子。这样的例子在JDBC操作中也非常的常见。(所以,我觉得对于资源的及时正确清理是一个程序员的基本素质之一。)

Try…finally结构也是保证资源正确关闭的一个手段。如果你不清楚代码执行过程中会发生什么异常情况会导致资源不能得到清理,那么你就用try对这段”可疑”代码进行包装,然后在finally中进行资源的清理。举一个例子:


public void readFile() {

BufferedReader reader = null;

try {

reader = new BufferedReader(new InputStreamReader(new FileInputStream("file")));

// do some other work

//close reader

reader.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

复制代码

我们注意一下这个方法和上一个方法的区别,下一个人可能习惯更好一点,及早的关闭reader。但是往往事与愿违,因为在reader.close()以前异常随时可能发生,这样的代码结构不能预防任何异常的出现。因为程序会在异常出现的地方跳出,后面的代码不能执行(这在上面应经用实例证明过)。这时我们就可以用try…finally来改造:


public void readFile() {

BufferedReader reader = null;

try {

try {

reader = new BufferedReader(new InputStreamReader(new FileInputStream("file")));

// do some other work

// close reader

} finally {

reader.close();

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

复制代码

及早的关闭资源是一种良好的行为,因为时间越长你忘记关闭的可能性越大。这样在配合上try…finally就保证万无一失了(不要嫌麻烦,java就是这么中规中矩)。

再说一种情况,假如我想在构造方法中打开一个文件或者创建一个JDBC连接,因为我们要在其他的方法中使用这个资源,所以不能在构造方法中及早的将这个资源关闭。那我们是不是就没辙了呢?答案是否定的。看一下下面的例子:


public class ResourceInConstructor {

BufferedReader reader = null;

public ResourceInConstructor() {

try {

reader = new BufferedReader(new InputStreamReader(new FileInputStream("")));

} catch (FileNotFoundException e) {

e.printStackTrace();

}

}

public void readFile() {

try {

while(reader.readLine()!=null) {

//do some work

}

} catch (IOException e) {

e.printStackTrace();

}

}

public void dispose() {

try {

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

复制代码

这一部分讲的多了一点,但是异常确实是看起来容易用起来难的东西呀,java中还是有好多的东西需要深挖的。

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @职坐标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论
本文作者 联系TA

擅长针对企业软件开发的产品设计及开发的细节与流程设计课程内容。座右铭:大道至简!

  • 370
    文章
  • 5792
    人气
  • 94%
    受欢迎度

已有17人表明态度,94%喜欢该老师!

进入TA的空间
名师指导直通车
  • 资料索取
    资料索取
  • 答疑解惑
    答疑解惑
  • 技术交流
    技术交流
  • 职业测评
    职业测评
  • 面试技巧
    面试技巧
  • 高薪秘笈
    高薪秘笈
TA的其他文章 更多>>
WEB前端必须会的基本知识题目
经验技巧 92% 的用户喜欢
Java语言中四种遍历List的方法总结(推荐)
经验技巧 89% 的用户喜欢
Java语言之SHA-256加密的两种实现方法详解
经验技巧 83% 的用户喜欢
Java语言里Hashmap序列化的一个坑
经验技巧 100% 的用户喜欢
WEB前端之webpack+nodejs+npm构建前端项目
经验技巧 100% 的用户喜欢
其他海同名师 更多>>
刘新华
刘新华 联系TA
实力型。激情饱满,对专业充满热情
吴翠红
吴翠红 联系TA
独创“教、学、练、测”循环教学模式
吕益平
吕益平 联系TA
熟悉企业软件开发的产品设计及开发
黄泽民
黄泽民 联系TA
擅长javase核心技术
程钢
程钢 联系TA
擅长大型企业商业网站开发和管理
经验技巧30天热搜词 更多>>

您输入的评论内容中包含违禁敏感词

我知道了

免费获取海同IT培训资料
验证码手机号,获得海同独家IT培训资料
获取验证码
提交

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    ICP许可  沪B2-20190160

站长统计