目录:

一、为什么使用异常:

二、异常体系:

三、异常的捕捉--try、catch、finally:

四、关于异常的题:

五、自定义异常:

六、异常链:

七、异常的使用误区:

八:throw、throws:

九:异常使用指南总结:


一、为什么使用异常:

异常的处理机制可以确保我们程序的健壮性,提高系统可用率。在我们的程序设计当中,任何时候任何地方都有可能会出现异常,在没有异常机制的时候我们是这样处理的:通过函数的返回值来判断是否发生了异常(这个返回值通常是已经约定好了的),调用该函数的程序负责检查并且分析返回值。虽然可以解决异常问题,但是这样做存在几个缺陷:

(1) 容易混淆。如果约定返回值为-1时表示出现异常,那么当程序最后的计算结果真的为-1呢?

(2)代码可读性差。将异常处理代码和程序代码混淆在一起将会降低代码的可读性。

(3)由调用函数来分析异常,这要求程序员对库函数有很深的了解。

在OOP中提供的异常处理机制是提供代码健壮的强有力的方式。使用异常机制它能够降低错误处理代码的复杂度,如果不使用异常,那么就必须检查特定的错误,并在程序中的许多地方去处理它,而如果使用异常,那就不必在方法调用处进行检查,因为异常机制将保证能够捕获这个错误,并且,只需在一个地方处理错误,即所谓的异常处理程序中。这种方式不仅节约代码,而且把“概述在正常执行过程中做什么事”的代码和“出了问题怎么办”的代码相分离。

二、异常体系:

1、Throwable:

从上面这幅图可以看出,Throwable是java语言中所有错误和异常的超类(万物即可抛)。它有两个子类:Error、Exception。分别表示错误和异常。其中异常Exception分为运行时异常(RuntimeException)和非运行时异常(编译时异常),也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。

2、Error:

一般是指 Java 虚拟机相关的问题,大多数与代码编写与执行操作无关,如系统崩溃、虚拟机出错误、动态链接失败、线程死锁等,这种错误无法恢复或不可能捕获,将导致应用程序中断,通常应用程序无法处理这些错误,因此应用程序不应该捕获Error对象,也无须在其throws子句中声明该方法抛出任何Error或其子类。

3、Exception:

Exception是程序可以处理的异常,可以分为运行时异常与非运行时异常:

(1)运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。运行时异常表示程序运行过程中可能出现的非正常状态,这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

出现运行时异常后,如果没有捕获处理这个异常(即没有catch),系统会把异常一直往上层抛,一直到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。

(2)非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。如IOException、SQLException等以及用户自定义的Exception异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch并处理,否则程序就不能编译通过。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。

三、异常的捕捉--try、catch、finally:

对于异常的捕捉,一般使用try、catch、finally 。try快包含着可能出现异常的代码块,catch块捕获异常后对异常进行处理,finally代码块不论程序是否发生异常,总是会执行,所以finally一般用来关闭资源。

接下来看一个很典型的笔试题例子:

public int test2() {int i = 1;try {System.out.println("try语句块中");return 1;} finally {System.out.println("finally语句块中");return 2;}}
运行结果是:
try语句块中
finally语句块中
2

从运行结果中可以发现,try中的return语句调用的函数先于finally中调用的函数执行,也就是说return语句先执行,finally语句后执行,所以,返回的结果是2。return并不是让函数马上返回,而是return语句执行后,将把返回结果放置进函数栈中,此时函数并不是马上返回,它要执行finally语句后才真正开始返回。

四、关于异常的题:

1、error和exception有什么区别?运行时异常与编译时异常的区别?(参考第2题回答)

2、Java中的异常处理机制的简单原理和应用:

(1)异常是指java程序运行时所发生的非正常情况或错误,Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:Error 和 Exception;

(2)Error 表示应用程序本身无法克服和恢复的一种严重问题,一般是指java虚拟机相关的问题,大多数与代码编写与执行操作无关,如系统崩溃、内存异常、虚拟机出错误、动态链接失败、线程死锁等,这种错误无法恢复或不可能捕获,通常应用程序无法处理这些错误,将导致应用程序中断。

(3)Exception表示程序还能够克服和恢复的问题,其中又分为运行时异常和编译时异常。运行时异常表示程序运行过程中可能出现的非正常状态,一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生,如数组脚本越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常(ClassCastException)。非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。如IOException、SQLException等以及用户自定义的Exception异常。

(4)Java为运行时异常和编译时异常提供了不同的解决方案,编译器强制编译时异常必须try..catch处理或用throws声明继续抛给上层调用方法处理,否则程序就不能编译通过,所以普通异常也称为checked异常,而运行时异常可以处理也可以不处理,所以,编译器不强制用try..catch处理或用throws声明,所以系统异常也称为unchecked异常。

4,请写出你最常见到的5个runtime exception:

NullPointerException——程序试图访问一个空的数组中的元素或访问空的对象中的 方法或变量时产生异常;

ArithmeticException——由于除数为0引起的异常;

ArrayIdexOutOfBoundsException——访问数组元素下标越界,引起异常;

IndexOutOfBoundsExcention——由于数组下标越界或字符串访问越界引起异常;

ClassCastException——当把一个对象归为某个类,但实际上此对象并不是由这个类 创建的,也不是其子类创建的,则会引起异常;

OutofMemoryException——用new语句创建对象时,如系统无法为其分配内存空 间则产生异常;

ClassNotFoundException——未找到指定名字的类或接口引起异常;

ArrayStoreException——当向数组中存放非数组声明类型对象时抛出。

NegativeArraySizeException——数组长度是负数,则产生异常;

IllegalMonitorStateException——监控器状态出错引起的异常;

SecurityException——由于访问了不应访问的指针,使安全性出问题而引起异常;

IOException——由于文件未找到、未打开或者I/O操作不能进行而引起异常;

CloneNotSupportedException——程序中的一个对象引用Object类的clone方法,但此对象并没有连接Cloneable接口,从而引起异常;

InterruptedException——当一个线程处于等待状态时,另一个线程中断此线程,从而引起异常;

NoSuchMethodException——所调用的方法未找到,引起异常;

IllegalAccessExcePtion——试图访问一个非public方法;

StringIndexOutOfBoundsException——访问字符串序号越界,引起异常;

NumberFormatException——字符的UTF代码数据格式有错引起异常;

IllegalThreadException——线程调用某个方法而所处状态不适当,引起异常;

FileNotFoundException——未找到指定文件引起异常;

EOFException——未完成输入操作即遇文件结束引起异常。

五、自定义异常:

Java确实给我们提供了非常多的异常,但是异常体系是不可能预见所有的希望加以报告的错误,所以Java允许我们自定义异常来表现程序中可能会遇到的特定问题,总之就是一句话:我们不必拘泥于Java中已有的异常类型。

       Java自定义异常的使用要经历如下四个步骤:

       1、定义一个类继承Throwable或其子类。

       2、添加构造方法(当然也可以不用添加,使用默认构造方法)。

       3、在某个方法类抛出该异常。

       4、捕捉该异常。

/** 自定义异常 继承Exception类 **/
public class MyException extends Exception{public MyException(){}public MyException(String message){super(message);}
}public class Test {public void display(int i) throws MyException{if(i == 0){throw new MyException("该值不能为0.......");}else{System.out.println( 2 / i);}}public static void main(String[] args) {Test test = new Test();try {test.display(0);System.out.println("---------------------");} catch (MyException e) {e.printStackTrace();}}
}

运行结果:

六、异常链:

在设计模式中有一个叫做责任链模式,该模式是将处理请求的多个对象链接成一条链,请求沿着这条链传递直到被接收、处理。同样Java异常机制也提供了这样一条链:异常链。

       每遇到一个异常信息,我们都需要进行try…catch,一个还好,如果出现多个异常呢?分类处理肯定会比较麻烦,那就一个Exception解决所有的异常吧。这样确实是可以,但是这样处理势必会导致后面的维护难度增加。最好的办法就是将这些异常信息封装,然后捕获我们的封装类即可。

       我们有两种方式处理异常,一是throws抛出交给上级处理,二是try…catch做具体处理。但是这个与上面有什么关联呢?try…catch的catch块我们可以不需要做任何处理,仅仅只用throw这个关键字将我们封装异常信息主动抛出来。然后在通过关键字throws继续抛出该方法异常。它的上层也可以做这样的处理,以此类推就会产生一条由异常构成的异常链。

       通过使用异常链,我们可以提高代码的可理解性、系统的可维护性和友好性。

       同理,我们有时候在捕获一个异常后抛出另一个异常信息,并且希望将原始的异常信息也保持起来,这个时候也需要使用异常链。

       在异常链的使用中,throw抛出的是一个新的异常信息,这样势必会导致原有的异常信息丢失,如何保持?在Throwable及其子类中的构造器中都可以接受一个cause参数,该参数保存了原有的异常信息,通过getCause()就可以获取该原始异常信息。

语法:

public void test() throws XxxException{try {//do something:可能抛出异常信息的代码块} catch (Exception e) {throw new XxxException(e);}}

示例:

public class Test {public void f() throws MyException{try {FileReader reader = new FileReader("G:\\myfile\\struts.txt");  Scanner in = new Scanner(reader);  System.out.println(in.next());} catch (FileNotFoundException e) {//e 保存异常信息throw new MyException("文件没有找到--01",e);}  }public void g() throws MyException{try {f();} catch (MyException e) {//e 保存异常信息throw new MyException("文件没有找到--02",e);}}public static void main(String[] args) {Test t = new Test();try {t.g();} catch (MyException e) {e.printStackTrace();}}
}

运行结果::

com.test9.MyException: 文件没有找到--02at com.test9.Test.g(Test.java:31)at com.test9.Test.main(Test.java:38)
Caused by: com.test9.MyException: 文件没有找到--01at com.test9.Test.f(Test.java:22)at com.test9.Test.g(Test.java:28)... 1 more
Caused by: java.io.FileNotFoundException: G:\myfile\struts.txt (系统找不到指定的路径。)at java.io.FileInputStream.open(Native Method)at java.io.FileInputStream.<init>(FileInputStream.java:106)at java.io.FileInputStream.<init>(FileInputStream.java:66)at java.io.FileReader.<init>(FileReader.java:41)at com.test9.Test.f(Test.java:17)... 2 more

如果在程序中去掉 e,也就是:throw new MyException("文件没有找到--02");那么异常信息就保存不了,运行结果如下

com.test9.MyException: 文件没有找到--02at com.test9.Test.g(Test.java:31)at com.test9.Test.main(Test.java:38)

七、异常的使用误区:

首先我们先看如下示例:该实例能够反映java异常的不正确使用:

        OutputStreamWriter out = null;java.sql.Connection conn = null;try {            //   标注1Statement stat = conn.createStatement();ResultSet rs = stat.executeQuery("select *from user");while (rs.next()){out.println("name:" + rs.getString("name") + "sex:"+ rs.getString("sex"));}conn.close();         //标注2out.close();} catch (Exception ex){    //标注3ex.printStackTrace();    //标注4}

1、标注1:

       对于这个try…catch块,真正目的是捕获SQL的异常,但是这个try块是不是包含了太多的信息了。这是我们为了偷懒而养成的代码坏习惯。有些人喜欢将一大块的代码全部包含在一个try块里面,因为这样省事,反正有异常它就会抛出,而不愿意花时间来分析这个大代码块有那几块会产生异常,产生什么类型的异常,反正就是一篓子全部搞定。这就想我们出去旅游将所有的东西全部装进一个箱子里面,而不是分类来装,虽不知装进去容易,找出来难啊!!!所有对于一个异常块,我们应该仔细分清楚每块的抛出异常,因为一个大代码块有太多的地方会出现异常了。

结论一:尽可能减小try块!!!

2、标注2:

       在这里你发现了什么?异常改变了运行流程!!不错就是异常改变了程序运行流程。如果该程序发生了异常那么conn.close(); out.close();是不可能执行得到的,这样势必会导致资源不能释放掉。所以如果程序用到了文件、Socket、JDBC连接之类的资源,即使遇到了异常,我们也要确保能够正确释放占用的资源。这里finally就有用武之地了:不管是否出现了异常,finally总是有机会运行的,所以finally用于释放资源是再适合不过了。

结论二:保证所有资源都被正确释放,充分运用finally关键词!!!

3、标注3:

       对于这个代码我想大部分人都是这样处理的。使用这样代码的人都有这样一个心理,一个catch解决所有异常,这样是可以,但是不推荐!为什么!首先我们需要明白catch块所表示是它预期会出现何种异常,并且需要做何种处理,而使用Exception就表示他要处理所有的异常信息,但是这样做有什么意义呢?

       这里我们再来看看上面的程序实例,很显然它可能需要抛出两个异常信息,SQLException和IOException。所以一个catch处理两个截然不同的Exception明显的不合适。如果用两个catch,一个处理SQLException、一个处理IOException就好多了。所以:

结论三:catch语句应当尽量指定具体的异常类型,而不应该指定涵盖涵盖范围太广的Exception类,不要一个Exception试图处理所有可能出现的异常!!!

4、标注4:

这里涉及到了两个问题,一是,捕获了异常不做处理,二是异常信息不够明确。

 4.1、捕获异常不做处理,就是我们所谓的丢弃异常。我们都知道异常意味着程序出现了不可预期的问题,程序它希望我们能够做出处理来拯救它,但是你呢?一句ex.printStackTrace()搞定,这是多么的不负责任对程序的异常情况不理不顾。虽然这样在调试可能会有一定的帮助,但是调试阶段结束后呢?不是一句ex.printStackTrace()就可以搞定所有的事情的!那么怎么改进呢?有四种选择:

(1)处理异常。对所发生的的异常进行一番处理,如修正错误、提醒。再次申明ex.printStackTrace()算不上已经“处理好了异常”.

(2)重新抛出异常。既然你认为你没有能力处理该异常,那么你就尽情向上抛吧!!!

(3)封装异常。这是我认为最好的处理方法,对异常信息进行分类,然后进行封装处理。

(4)不要捕获异常。

4.2、异常信息不明确。我想对于这样的:java.io.FileNotFoundException: ………信息除了我们IT人没有几个人看得懂和想看吧!所以在出现异常后,我们最好能够提供一些文字信息,例如当前正在执行的类、方法和其他状态信息,包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。起码我公司是需要将异常信息所在的类、方法、何种异常都需要记录在日志文件中的。

结论四:既然捕获了异常,就要对它进行适当的处理,不要捕获异常之后又把它丢弃,不予理睬!!!

结论五:在异常处理模块中提供适量的错误原因信息,组织错误信息使其易于理解和阅读!!!

       对于异常还有以下几个注意地方:

结论六:不要在finally块中处理返回值!!!

结论七:不要在构造函数中抛出异常!!!

八:throw、throws:

throws是方法抛出异常。在方法声明中,如果添加了throws子句,表示该方法即将抛出异常,异常的处理交由它的调用者,至于调用者任何处理则不是它的责任范围内的了。所以如果一个方法会有异常发生时,但是又不想处理或者没有能力处理,就使用throws吧!

而throw是语句抛出异常。它不可以单独使用,要么与try…catch配套使用,要么与throws配套使用。

//使用throws抛出异常public void f() throws MyException{try {FileReader reader = new FileReader("G:\\myfile\\struts.txt");  Scanner in = new Scanner(reader);  System.out.println(in.next());} catch (FileNotFoundException e) {throw new MyException("文件没有找到", e);    //throw}  }

九:异常使用指南总结:

应该在下列情况下使用异常(摘自:Think in java):

       1、在恰当的级别处理问题(在知道该如何处理异常的情况下才捕获异常)。

       2、解决问题并且重新调用产生异常的方法。

       3、进行少许修补,然后绕过异常发生的地方继续执行。

       4、用别的数据进行计算,以代替方法预计会返回的值。

       5、把当前运行环境下能做的事情尽量做完。然后把相同(不同)的异常重新抛到更高层。

       6、终止程序。

       7、进行简化。

       8、让类库和程序更加安全。(这既是在为调试做短期投资,也是在为程序的健壮做长期投资)

参考博客以及转载博客地址:

https://blog.csdn.net/chenssy/article/details/17651909

https://blog.csdn.net/qq_22860341/article/details/73610537

https://blog.csdn.net/huhui_cs/article/details/38817791

https://blog.csdn.net/chenssy/article/details/17651971

Java基础篇:异常机制相关推荐

  1. Java基础:异常机制

    最近开始了找工作的面试,在面试过程中,面试官问了关于Java当中的异常处理机制,一直以来,无论写代码还是看书,自己对异常处理这一块就没有很好的重视过,对它的认知也仅仅停留在通过Try-catch去进行 ...

  2. Java 语言基础(异常机制和File类,IO流,多线程,网络编程,反射机制)

    原文:Java 语言基础(异常机制和File类,IO流,多线程,网络编程,反射机制) 异常机制和File类 异常机制 基本概念 异常就是"不正常"的含义,在 Java 语言中主要指 ...

  3. 菜鸟学习笔记:Java基础篇7(包装类、时间相关类、文件类、异常处理类)

    菜鸟学习笔记:Java其他常用类 基本数据类型包装类 时间处理和文件处理相关类 Date时间类 SimpleDateFormat Calendar日历类 文件类 异常机制 异常的概念 Java异常处理 ...

  4. Android面试题Java基础篇

    Android面试题Java基础篇,由本人整理汇总,后续将继续推出系列篇,如果喜欢请持续关注和推荐,更多精彩内容可以关注微信公众号(Android高级编程):android-tech 系列文章目录: ...

  5. 《Java 后端面试经》Java 基础篇

    <Java 后端面试经>专栏文章索引: <Java 后端面试经>Java 基础篇 <Java 后端面试经>Java EE 篇 <Java 后端面试经>数 ...

  6. 【程序员养成之路】Java基础篇 8-流进流出的IO流(二)

    以下内容若有误,欢迎私信我或在下方留言,谢谢^_− 目录 IO流(二) 1.特殊操作流 1.1 标准流 1.2 打印流 1.3 对象序列化流 1.4 Properties 拓展1:比较字节流和字节缓冲 ...

  7. 高频面试真题答案 -java后端 -java基础篇

    原贴 2022届秋招高频面试真题汇总,千题奉送!!!- 后端篇_笔经面经_牛客网 整理答案: 类加载机制 47 双亲委派机制 24 new一个对象的过程 4 java程序是如何运行起来的? 1 jvm ...

  8. 你所需要的java基础篇深入解析大汇总

    java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...

  9. Java基础知识——异常Throwable和Exception

    Java基础知识--异常Throwable和Exception Java设置了异常,旨在鼓励将方法中可能出现的异常告知给使用此方法的程序员(你和我!).当然了,这种方法是比较优雅的,让我们确切的知道是 ...

  10. Java基础篇1——变量与数据类型

    Java基础篇1--变量与数据类型 1.标识符命名规则 标识符以由大小写字母.数字.下划线(_)和美元符号($)组成,但是不能以数字开头. 大小写敏感 不能与Java语言的关键字重名 不能和Java类 ...

最新文章

  1. SMRT single molecular real time Sequencing
  2. 一文读懂深响年度大会,增长密码藏在这些关键词里
  3. Python的regex模块——更强大的正则表达式引擎
  4. 临床预测模型开发checklist详解
  5. linux cookie 地址,SYN Cookie原理及其在Linux内核中的实现
  6. node js 技术架构_[视频] Node JS中的干净架构
  7. 示波器纹波测试的时间设置_500W电源横评:输出纹波3款电源超标
  8. JAVA开发面试常问问题总结3
  9. 研究多个基因间相互作用的频域方法
  10. 计算机硬件 中级证,计算机硬件组装与教学方法计算机应用中级职称论文
  11. 建立项目工作节奏之华为时间管理大法
  12. jquery bootstrap-select多选组件使用指南
  13. 用opencv将左右眼3D图片转换为红蓝3D图片
  14. C# 定时任务 调度框架 WebWork (Quartz.NET) Web版的Windows服务
  15. Flask中 jsonify有什么作用?如何使用?
  16. mysql存储过程出参和入参_数据库mysql存储中的入参出参理解
  17. iPhone12大概率不送充电器了
  18. Windows11不显示WiFi图标
  19. 2021年焊工(初级)考试报名及焊工(初级)证考试
  20. 电脑开机安装流氓软件、弹广告处理办法

热门文章

  1. 八十八、从斐波那契数列和零一背包问题探究动态规划
  2. mysql 笔试题_MySQL笔试题详解(一)(中等难度)
  3. 《失控玩家》爆火背后:什么才是拥抱人工智能的正确姿势?
  4. 2017年度最值得读的AI论文 | NLP篇 · 评选结果公布
  5. 本期最新 9 篇论文,帮你完美解决「读什么」的问题 | PaperDaily #19
  6. imagenet数据格式以及python文件处理的一些函数
  7. MybatisPlus操作模板
  8. jQuery中设置树节点被选中
  9. Vuex——命名空间导致错误[unknown action type:XXX]解决方案
  10. Suffix Zeroes