Java基础——异常机制


【捕获异常】

硬件的错误、输入错误、物理限制等问题,都可能导致程序运行时的异常出现。

1.异常的分类层次

在java中,异常对象都是由Throwable类继承而来的,主要分为两大类:

Error和Exception类。

在Exception中又分为:

RuntimeException异常和非RuntimeException异常。

异常的分类有以下几种:

1.Error类层次的结构主要描述了java运行时系统的内部错误和资源耗尽等错误,如硬件错误、输入错误数据、系统崩溃等。出现这些系统内部的问题,除了通知用户并尽量安全退出,基本上程序员也无能为力了,所以这种情况一般不要求解决,当然,这种情况也很少出现。

2.RuntimeException的异常时指运行时异常,也称为未检查异常。一般是由于程序员自己的问题造成的,如错误的类型转换、数组访问越界、访问空指针等。这些都是可以通过程序员的细心处理和认真分析来避免的。如在转换类型时检查,通过检查下标来防止越界,使用变量前检查是否为空来杜绝空指针异常。

3.非RuntimeException异常,也就是已检查异常。常见的已检查异常主要有以下几种:java.io.IOEeception(IO异常,输入输出设备不存在,比如在文件的末尾读取数据)和java.io.FileNotFoundException(文件未找到异常)和java.lang.ClassNotFoundException(动态地装载某个类时,找不到此类)

注意:对于已检查异常必须处理,对于未检查异常可以处理也可以不处理

Java异常类层次结构图:

2.捕获和处理异常

语法规则:

  • 返回类型 方法名(参数)
  • {
  • try {
  • 可能出现的异常语句A
  • 可能出现的异常语句B
  • 可能出现的异常语句C
  • }
  • catch(异常类 e) {
  • //某种异常的引用
  • 异常处理的语句D
  • }
  • finally {
  • 最终一定会执行的语句E
  • }
  • 其他语句F
  • }

finally语句块内的语句无论在什么时候在什么情况下都会被执行,经常会写一些释放资源的语句。如果前面语句中有一个return的值,finally中也有一个return的值,那么返回的一定是fianlly中return的值。

finally和catch可以省略其中的一个,但是不能同时省略

示例:

  • public class ExceptionTest {
  • public static void main(String[] args) {
  • //写一个for循环和switch分支语句,一次运行会抛出异常的语句
  • for(int i = 0;i < 5;i++) {
  • int j = 0;
  • try {
  • System. out.println("本条语句正常" );
  • //每次运行1条语句,前4条抛出异常,最后一条不抛出异常
  • switch(i) {
  • case 0:   int zero = 0;
  • j = 1/zero; break;
  • case 1:   int b[] = null;
  • j = b[0]; break;
  • case 2: int c[] = new int [2];
  • j = c[3]; break;
  • case 3:   char ch = "hello".charAt(9); break;
  • case 4:   char cha = "abc".charAt(1); break;
  • }
  • System. out.println("前面的语句都没有异常抛出才会运行我" );
  • } catch(Exception e) {
  • System. out.println("第" + (i+1) + "次捕获异常");
  • System. out.println("显示的异常信息为:" + e);
  • } finally {
  • System. out.println("无论前面怎样,这条语句都会执行" );
  • }
  • }
  • }
  • }

上面代码中case的前四句话必定会抛出异常:

case:0是零做了除数;

case:1是数组没有赋值,也就是没有初始化就使用

case:2是数组越界

case: 3是字符串越界

结果:

3.异常的匹配

如果try语句后跟多个catch语句,那么排列的先后顺序如下所示:

1.如果多个catch语句块中所指定的异常类型级别相同或者没有任何派生关系,则catch语句排列无序。
2.如果多个catch语句块中所指定的异常类型相互之间有派生关系,则必须子类型的异常写在上面,父类型的异常写在下面。


【自定义和抛出异常】

1.自定义异常

当系统中已有的异常类型不能满足使用要求时,可以根据自己的需要抛出自定义异常的对象。
自定义异常类一般通过充当捕获异常的角色,所以从Exception类或者其他的捕获异常类继承就可以了
其语法格式如下:

  • class 类名 extends Exception {
  • 类体;
  • }

自定义的异常类一般都会编写必要的构造方法和一些适当的功能方法,而且一般都会有两个构造方法:

一个是无参的构造方法

一个是以字符串做参数的构造方法

以字符串做参数的构造方法可以在有出错信息的情况下创建异常对象。

示例:

  • //自定义异常类ReportNotFoundException,有两个构造方法
  • public class ReportNotFoundException extends Exception{
  • ReportNotFoundException() {
  • }
  • ReportNotFoundException(String mesg) {
  • super(mesg);//创建异常对象
  • }
  • }

2.抛出异常

在声明或者方法中抛出异常,主要内容和使用方法如下:
在编程中会遇到很多异常,如果该程序有能力解决,可以用try/catch方法主动获取和处理异常。当不具备对异常进行处理的能力时,则向上抛出异常,直到抛到能够处理异常的位置。

抛出异常的语法是:

  • 访问限制修饰符 [static] 方法名(参数列表) throws 异常序列 {
  • 方法体;
  • }

比如,有一个m方法抛出了IOException和InterruptedException。
代码如下:

  • public void m() throws IOException,InterruptedException {
  • 方法体;
  • }

throws用来声明该方法将有可能抛出的异常,将可能抛出的异常列在throws后面,用逗号隔开

在方法体中处理异常的时候,也可以将这两种捕获异常再抛出,使用throws语句就可以将一个异常对象抛出
语法格式为:

  • throw new 异常对象;

当一个方法中出现异常,而没有处理,则以异常对象为返回值返回调用处,然后逐级传递。如果一直没有捕获和处理,最终异常将返回虚拟机,虚拟机终止退出,程序结束。

示例:

自定义异常:

  • //自定义异常类ReportNotFoundException,有两个构造方法
  • public class ReportNotFoundException extends Exception{
  • ReportNotFoundException() {
  • }
  • ReportNotFoundException(String mesg) {
  • super(mesg);//创建异常对象
  • }
  • }

职员及相应方法:

  • public class Employee {//定义公开的职员类型
  • String name;
  • public Employee(String name) {
  • this.name = name;
  • }
  • public String getReport() throws ReportNotFoundException {
  • //定义职员找报表的方法,找不到报表就报自定义异常
  • if(Math.random() > 0.7) {//设定找到报表的几率是70%
  • throw new ReportNotFoundException(name + "找不到报表" );
  • }
  • return name + ",报表找到了" ;
  • }
  • }
  • class Manager {//定义经理类
  • Employee[] es;//职员数组
  • public Manager(Employee[] es) {
  • super();
  • this.es = es;
  • }
  • public String getReport() throws ReportNotFoundException {
  • //定义经理找报表的方法
  • StringBuffer sb = new StringBuffer();//StringBuffer定义经常变化的字符串
  • for(int i = 0;i < es.length;i++) {
  • sb.append( es[i].getReport());//经理让所有职员找报表
  • }
  • return sb.toString();
  • }
  • }
  • class CFO {//定义CFO类
  • Manager[] ms;
  • public CFO(Manager[] ms) {
  • super();
  • this.ms = ms;
  • }
  • public String getReport() {//CFO的找报表方法,CFO只找下面的经理要报表
  • try {
  • return ms [0].getReport();
  • } catch(ReportNotFoundException e) {
  • e.printStackTrace();//打印异常栈信息
  • }
  • return null ;
  • }
  • }
  • class CEO {//定义CEO类
  • CFO cfo;
  • public CEO(CFO cfo) {
  • super();
  • this.cfo = cfo;
  • }
  • public String getReport() {//CEO的找报表方法,调用CFO去找报表
  • return cfo.getReport();
  • }
  • }

测试:

  • //测试向上抛出方法和自定义异常
  • public class ExceptionTest2 {
  • public static void main(String[] args) {
  • Employee emone = new Employee("员工一");//创建员工对象
  • Employee emtwo = new Employee("员工二");
  • Employee emthree = new Employee("员工三");
  • Employee[] employees = new Employee[] {emone,emtwo,emthree};//创建员工数组
  • Manager[] managers = new Manager[] {new Manager(employees)};//创建经理数组
  • CFO cfo = new CFO(managers );//创建CFO对象
  • CEO ceo = new CEO(cfo);//创建CEO对象
  • System. out.println(ceo.getReport());//ceo对象调用找报表方法
  • }
  • }

结果:


小结:

  • try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
  • catch 块:用于处理try捕获到的异常。
  • finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。

在以下4种特殊情况下,finally块不会被执行:

1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。

  • try-catch-finally 规则(异常处理语句的语法规则):

1)  必须在 try 之后添加 catch 或 finally 块。try 块后可同时接 catch 和 finally 块,但至少有一个块。
2) 必须遵循块顺序:若代码同时使用 catch 和 finally 块,则必须将 catch 块放在 try 块之后。
3) catch 块与相应的异常类的类型相关。
4) 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块,不会再执行其他的 catch代码块
5) 可嵌套 try-catch-finally 结构。
6) 在 try-catch-finally 结构中,可重新抛出异常。

  • try、catch、finally语句块的执行顺序:

1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;

2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;

3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;

  • Throws抛出异常的规则:

1) 如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。

2)必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误

3)仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。

4)调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

  • 常见异常

在Java中提供了一些异常用来描述经常发生的错误,对于这些异常,有的需要程序员进行捕获处理或声明抛出,有的是由Java虚拟机自动进行捕获处理。Java中常见的异常类:

1.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文件时,抛出该异常。

5、java.lang.NegativeArraySizeException

数组长度为负异常

6、java.lang.ArrayStoreException

数组中包含不兼容的值抛出的异常

7、java.lang.SecurityException

安全性异常

8、java.lang.IllegalArgumentException

非法参数异常

2.IOException

1、IOException:

操作输入流和输出流时可能出现的异常。

2、EOFException

文件已结束异常

3、FileNotFoundException

文件未找到异常

3. 其他

1、ClassCastException

类型转换异常类

2、ArrayStoreException

数组中包含不兼容的值抛出的异常

3、SQLException

操作数据库异常类

4、NoSuchFieldException

字段未找到异常

5、NoSuchMethodException

方法未找到抛出的异常

6、NumberFormatException

字符串转换为数字抛出的异常

7、StringIndexOutOfBoundsException

字符串索引超出范围抛出的异常

8、IllegalAccessException

不允许访问某类异常

9、InstantiationException

当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常

时间: 2024-10-07 20:54:18

Java基础——异常机制的相关文章

黑马程序员——java基础——异常

黑马程序员--java基础--异常 ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 异常 就是不正常.程序在运行时出现的不正常情况.其实就是程序中出现的问题.这个问题按照面向对象思想进行描述,并封装成了对象.因为问题的产生有产生的原因.有问题的名称.有问题的描述等多个属性信息存在.当出现多属性信息最方便的方式就是将这些信息进行封装.异常就是java按照面向对象的思想将问题进行对象封装. 异常体系 --------java.lang.Thro

Java基础——异常(2)

throws 和 throw 有什么区别? 1.位置不同:throws用在函数上,后面跟的是异常类,可以跟很多个. throw用在函数内,后面跟的是异常对象. 2.功能不同:throws用来声明异常,让调用者知道功能有可能出现问题,并由调用者可以给出预先的处理方式. throw抛出具体问题对象.执行到throw功能已经结束了,跳转到调用者(谁调用跳哪去),并将具体的问题对象抛给了调用者. 异常体系最大的特点就是体系中的类以及类产生的对象,都具备可抛性.可抛性的意思就是可以被throws和thro

关于java中异常机制

什么是异常:异常就是程序在运行时出现的不正常情况.对于严重的情况Java通过Error类进行描述,一般不用编写代码处理:对于不严重的情况Java通过Exception描述,一般编写针对性代码对其进行处理. 异常由来:问题也是生活中一个具体的事物,也可以通过Java类的形式进行描述(比如进行运算时被除数不可以为0否则出现ArithmeticException异常,数组越界会出现ArrayIndexOutOfBoundsException等等),并封装成对象.即Java对不正常情况进行描述后的对象体

java基础 异常学习笔记

1.异常是导致程序中断运行的一种指令流,如果不对异常进行正确的处理,则可能导致程序中断执行,造成不必要的损失,所以在程序的设计中必须要考虑各种异常的发生,并正确的做好相应的处理,这样才能保证程序正确的执行. 2.一旦产生异常之后,异常之后的语句并不会执行,而是直接结束程序,并将错误报告给用户. 3.在计算机发展史有两大杀手:断电,被除数为0(结果为无穷大,则程序内容会被全部占满). 处理异常的格式: try{// 可能出现异常的语句} catch(异常类异常对象){//编写异常的处理语句} ca

Java基础——异常(3)

小节: 异常其实就是将问题进行封装,抛给调用者. 如果声明了,就需要调用者处理(继续抛或者捕获). 什么时候声明?什么时候捕获? 功能内部可以解决就捕获,不能解决或者解决还必须告诉调用者问题,这时就应该声明. finally的作用:无论是否有异常发出,都需要资源进行释放.资源释放就是定义在finally的代码块中. 练习:老师用电脑上课.电脑可能出现的问题是:电脑蓝屏.电脑冒烟. 异常转换:根据不同的对象产生不同的异常. 封装本层异常,对外暴露对方能处理的异常. 覆盖时: 子类方法覆盖父类方法只

Java基础—异常

一.  Exception异常 1. 概述 异常是程序在运行时出现的错误 异常由来:问题也是现实生活中一个具体的事物,也可以通过java的类的形式进行描述.并封装成对象. 其实就是java对不正常情况进行描述后的对象体现. 2. Java的异常体系 1. 从图中可以看出Throwable下有两个子类,Error和Exception 对于严重的问题,java通过Error类进行描述.对Error类一般不编写针对性的代码对其进行处理. 对于非严重的,java通过Exception类进行描述.对于Ex

Java的异常机制

一.什么是异常:非正常的,不同寻常的,不是语法错误. 生活中,医生说你身体某个部位异常,该部位和正常相比,有点不同功能可能受损. 张三开车去上班,正常情况下,顺利到达公司 非正常情况下,车子坏了,走路去公司 异常指的 不是语法错误 ,语法错误编译通不过,不会产生字节码文件,根本不能运行 程序中:代码出现错误,程序就会停止运行. 异常处理是衡量一门语言是否成熟的标准之一.主流的java c++ c# 都有异常处理机制. 异常处理可以让程序有更好的容错性,使代码更健壮. 传统的c语言是没有异常处理的

Java基础——异常体系

在Java中,异常对象都是派生于Throwable类的一个实例,Java的异常体系如下图所示: 所有的异常都是由Throwable继承而来,在下一层立即分解为两个分支,Error和Exception. Error错误:描述了Java运行时系统的内部错误和资源耗尽错误.一般是指虚拟机相关的问题,如系统崩溃,虚拟机出错误等,这种错误无法恢复或不可能捕获,将导致应用程序中断,通常不处理.因为如果出现这样的内部错误,除了通告用户,并尽力使程序安全地终止之外,再也无能为力了. Exception异常:Ja

八、java中异常机制

一.为什么要有异常处理机制? java中的异常处理机制简单的讲就是try..catch..finally的使用. 程序难免会出现错误, 如果没有异常处理机制, 那么程序员在编写代码的时候就必须检查特定的结果, 并在程序的很多地方去处理它. 有了异常处理机制后,就不必在每个方法调用处都检查, 只需要用try包裹住可能发生异常的代码段, 这样做的好处是: 1.降低了代码的复杂度,正如上面所说的,不需要每个方法调用处都去检查: 2.将“描述正常情况下应该做什么事情”和“如果出了错怎么办” 的逻辑分开: