第八章 异常处理

目录

8.1 异常概述

例8.1

8.2  异常的分类

8.2.1  系统错误——Error

8.2.2  异常——Exception

例8.2

例8.3

8.3  捕捉处理异常

8.3.1 try.. .catch代码块

例8.4

8.3.2  finally代码块

例8.5

8.4  在方法中抛出异常

8.4.1  使用whrows关键字抛出异常

例8.6

8.4.2  使用throw关键字抛出异常

例8.7

​8.5  自定义异常 

例8.8

8.6  异常的使用原则

8.7  小结

8.1 异常概述

        在程序中,错误可能产生于程序员没有预料到的各种情况,或者是超出了程序员可控范围的环境因素,如试图打开一个根本不存在的文件等,在Java中,这种在程序运行时可能出现的一些错误称为异常。Java 语言的异常处理机制优势之一就 是可以将异常情况在方法调用中进行传递,通过传递可以将异常情况传递到合适的位置再进行处理,这种机制类似于现实中发现了火灾,一个人是无法扑灭大火的,那么可以将这种异常情况传递给119, 119 再将这个情况传递给附近的消防队,消防队及时赶到并进行灭火。使用这种处理机制,使得Java语言的异常处理更加灵活,Java语言编写的项目更加稳定。当然,异常处理机制也存在一些弊端, 例如,使用异常处理可能会降低程序的执行效率,增加语法复杂度等。接下来通过一个案例认识一下什么 是异常。

例8.1

public class Baulk {    //创建类     
    public static void main(String[] args) {      //主方法
        // TODO Auto-generated method stub
int result=3/0;                 //定义int型变量并赋值
System.out.println(result);     //将变量输出
    }
}

        程序运行的结果报告发生了算术异ArithmeticException (根据给出的错误提示可知发生错误是因为在算术表达式“3/0” 中,0作为除数出现),系统不再执行下去,提前结束。这种情况就是所说的异常。

        有许多异常的例子,如空指针、数组溢出等。由于Java语言是一门面向对象的编程语言,因此,异常在Java语言中也是作为类的实例的形式出现的。当某一方法中发生错误时,这个方法会创建一个对象,并且把它传递给正在运行的系统。这个对象就是异常对象。通过异常处理机制,可以将非正常情况下的处理代码与程序的主逻辑分离,即在编写代码主流程的同时在其他地方处理异常。

8.2  异常的分类

        Java类库的每个包中都定义了异常类,所有这些类都是Throwable 类的子类。Throwable 类派生了两个子类,分别是Error类和Exception类,其中,Error 类及其子类用来描述Java运行系统中的内部错误以及资源耗尽的错误,这类错误比较严重。Exception 类称为非致命性类,可以通过捕捉处理使程序继续执行。Exception 类又可以根据错误发生的原因分为运行时异常和非运行时异常。Java中的异常类继承

8.2.1  系统错误——Error

        Error 类及其子类通常用来描述Java运行系统中的内部错误,该类定义了常规环境下不希望由程序捕获的异常,比如OutOfMemoryError. ThreadDeath 等,这些错误发生时,Java 虚拟机(JVM)一般 会选择线程终止。

    public static void main(String[] args) { 
        System.out.println("梦想照亮现实!!!")   //此处缺少必要的分号
    }

错误提示

        从图8.3的提示可以看到显示的异常信息为"java.lang. Error”,说明这是- -个系统错误,程序遇到这种错误,通常都会停止执行,而且这类错误无法使用异常处理语句处理。

8.2.2  异常——Exception

        Exception是程序本身可以处理的异常,这种异常主要分为运行时异常和非运行时异常,程序中应当尽可能去处理这些异常,本节将分别对这两种异常进行讲解。、

1.运行时异常

        运行时异常是程序运行过程中产生的异常,它是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException 等,这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

         例如,将一个字符串转换为整型,可以通过Integer 类的parseInt0方法来实现。 如果该字符串不是数字形式,parseInt0方法就会显示异常,程序将在出现异常的位置终止,不再执行下面的语句。

例8.2

public class Thundering {   //创建类
    public static void main(String[] args) {     //主方法
        // TODO Auto-generated method stub
String str ="lili";    //定义字符串
System.out.println(str+"年龄是:");     //输出的提示信息
int age=Integer.parseInt("20L");      //数据类型的转换
System.out.println(age);         //输出信息
}
 
}

        本实例报出的是NmbeFforFrmalExcpticon (字符串转换为数字)异常,该异常实质上是由于开发人员的逻辑错误造成的。

2.非运行时异常
        非运行时异常是RuntimeException类及其子类异常以外的异常。从程序语法角度讲,这类异常是必须进行处理的异常,如果不处理,程序就不能编译通过,如TOException、SQLException以及用户自定义的异常等。

例8.3

package 第八章;
 
public class li83 {
	private int playerNum;
	private String teamName;
	public li83()
	{
		try {
			Class.forName("com.mrsoft.Coach");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.print("未找到");
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		li83 team=new li83();
		team.teamName="com.mrsoft";
		team.playerNum=19;
		System.out.println("\n球队名称:"+team.teamName+"\n"+"球员数量:"+team.playerNum+"名");
	}
 
}

  

8.3  捕捉处理异常

        前面讲解非运行时异常时,提到了系统会自动为非运行时异常提供两种解决方案,一种是使用h owS 关键字,一种是使用ty..atch代码块,这两种方法都是用来对异常进行处理的,本节首先w对..cach代码块进行讲解。

tr.. .atch 代码块主要用来对异常进行捕捉并处理。在实际使用时,该代码块还有一个可选的fnallyy 代码块,其标准语法如下:

try{
//程序代码块
}
catch (Exceptiontype e) {
//对Exceptiontype的处理
}
finally{
//代码块
}

        其中,try 代码块中是可能发生异常的Java代码; catch 代码块在try代码块之后,用来激发被捕获的异常; finally 代码块是异常处理结构的最后执行部分,无论程序是否发生异常,fnally 代码块中的代码都将执行,因此,在finally代码块中通常放置一些释放资源、 关闭对象的代码。
通过t...ca.ch代码块的语法可知,捕获处理异常分为try..catch代码块和fnally代码块两部分,下面分别进行讲解。

8.3.1 try.. .catch代码块

例8.4

         从图8.6中可以看出,程序仍然输出最后的提示信息,没有因为异常而终止。在例8.4中将可能出现异常的代码用try... catch代码块进行处理,当try代码块中的语句发生异常时,程序就会跳转到catch代码块中执行,执行完catch代码块中的程序代码后,将继续执行catch代码块后的其他代码,而不会执行try代码块中发生异常语句后面的代码。由此可知,Java的异常处理是结构化的,不会因为个异常影响整 个程序的执行。
上面代码中,在catch代码块中使用了Exception对象的pitackTace0方法输出了异常的栈日志,除此之外,Exeptin对象还提供了其他的方法用于获取异常的相关信息,其最常用的3个方法如下。

(1)getMessage()方法:获得有关异常事件信息。

(2)toString()方法:获取异常的类型与性质。

(3)printStackTrace()方法:获取异常事件发生时执行堆积内容。

        虽然try代码块后面用了一个catch代码块来捕捉异常,但是遇到需要处理多种异常信息的情况时,可以在一个try代码块后面跟多个catch代码块。这里需要注意的是,如果使用多个catch代码块,则catch代码块中的异常类顺序是先子类后父类,因为父类的引用可以引用子的对象,例如,修改例8.4, 使其能够分别捕捉NumberFormatException 异常和除NumberFormaException以外的所有异常。

        该错误就是由于使用多个catch代码块时,父异常类放在了子异常类前面所引起的,因为Exception是所有异常类的父类,如果将catch代码块放在catch(NumberFormatException nfx)的前面,后面的代码块将永远得不到执行,也就没有什么意义了,所以catch代码块的顺序不可调。

8.3.2  finally代码块

        完整的异常处理语句应该包含finally 代码块,通常情况下,无论程序中有无异常发生,finally代码块中的代码都可以正常执行

例8.5

public class T_23 {
    public static void main(String[] args) {//主函数
        try { // try语句中包含可能出现异常的程序代码
            String str = "lili"; // 定义字符串变量
            System.out.println(str + "年龄是:"); // 输出的信息
            int age = Integer.parseInt("20L"); // 数据类型转换
            System.out.println(age);//输出age
        } catch (Exception e) { // catch代码块用来获取异常信息
            e.printStackTrace(); // 输出异常性质
        }
        System.out.println("program  over"); // 输出信息
    }
}

        从图8中可以看出,程序在指提完异常信息之后,会执行fmy代的中的代码。另外,心下了种特殊情况下,fnally 块不会被执行。

(1)在fnally代码块中发生了异常。
(2)在前面的代码中使用了System.exit(退 出程序。
(3)程序所在的线程死亡。

8.4  在方法中抛出异常

        如果某个方法可能会发生异常,但不想在当前方法中处理这个异常,则可以使用throws、throw关键字在方法中抛出异常,本节将对如何在方法中抛出异常进行讲解。

8.4.1  使用whrows关键字抛出异常

        throws关键字通常被应用在声明方法时,用来指定方法可能抛出的异常,多个异常可使用逗号分隔。使用throws关键字抛出异常的语法格式为:

返回值类型名方法名(参数表)throws异常类型名{
方法体
}

例8.6

public class T_24 {    //创建类
    static void pop() throws NegativeArraySizeException {// 定义方法并抛出NegativeArraySizeException异常
        int[] arr = new int[-3]; // 创建数组
    }
    public static void main(String[] args) { // 主方法
        try { // try语句处理异常信息
            pop(); // 调用pop()方法
        } catch (NegativeArraySizeException e) {//处理异常
            System.out.println("pop()方法抛出的异常"); // 输出异常信息
        }
    }
}

  

        如果方法抛出了异常,在调用该方法时,必须为捕捉的方法处理异常,当然,如果使用throws关键字将异常抛给上一级后,不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的代码。例如,例8.6的代码中,如果在调用pop0方法时,没有处理 NegativeArraySizeException异常,而是处理了其他的异常,比如NullPointerException异常,代码修改如下:

try{                            //try语句处理异常信息

pop();             //调用pop()方法

} catch (NullpointerException e){
system.out.println("pop()方法抛出的异常:");     //输出信息

}

8.4.2  使用throw关键字抛出异常

        throw关键字通常用于在方法体中“制造”一个异常,程序在执行到throw语句时立即终止,它后面的语句都不执行。使用throw关键字抛出异常的语法格式为:

throw new异常类型名(异常信息)

throw通常用于在程序出现某种逻辑错误时,由开发者主动抛出某种特定类型的异常,下面通过一个实例介绍throw的用法。

例8.7

public class T_27 {
    public static void main(String[] args) { // 主方法
        int num1 = 25;//定义int类型的num赋值为25
        int num2 = 0;//定义int类型的num赋值为0
        int result;//定义int类型的result
        if (num2 == 0) // 判断num2是否等于0,如果等于0,抛出异常
        {
            throw new ArithmeticException("这都不会,小学生都知道:除数不能是0!!!");    // 抛出ArithmeticException异常
        }
        result = num1 / num2; // 计算int1除以int2的值
        System.out.println("两个数的商为:" + result);//输出"两个数的商为:" + result
    }
}


8.5  自定义异常 

        使用Java内置的异常类可以描述在编程时出现的大部分异常情况,但是有些情况是通过内置异常类无法识别的,例如,下面的一段代码: 

int  age =-50:
System. out.println("王师傅今年"+age+" 岁了! ");

        上面代码运行时没有任何问题,但是大家想一想: 人的年龄可能是负数吗?这类问题编译器是无法识别的,但很明显不符合常理,那么,对于这类问题即可通过自定义异常对它们进行处理。Java中可以通过继承Exception 类自定义异常类。

(1)创建自定义异常类。
(2)在方法中通过throw关键字抛出异常对象。
(3) 如果在当前抛出异常的方法中处理异常,可以使用try. .catch代码块捕获并处理,否则,在方法的声明处通过throws关键字指明要抛给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。
有了自定义异常,再来解决年龄为负数的异常问题。

例8.8

public class MyException extends Exception{//创建自定义异常,继承Exception类
 public MyException (String ErrorMessage) {//构造方法
  super (ErrorMessage);//父类构造方法
 }
}
public class Tran {//创建类
 static void avg(int age) throws  MyException{//抛出MyException异常错误
    if(age<0) {      //判断方法中参数是否满足指定条件
     throw new MyException("年龄不可以使用负数");//错误信息
    }else {                  //反之
     System.out.println("王师傅今年"+ age +"岁了!");//输出王师傅今年多少岁了
    }
 }
     public static void main(String[] args) { // 主方法
      try {     //try代码块处理可能出现异常的代码
       avg(-50);              //负数
      }catch(MyException e) {   //捕捉错误信息
       e.printStackTrace();   //输出异常性质
      }
  }
}

 自定义异常主要用在以下场合。

(1)使异常信息更加具体,比如跟别人合作开发时,程序出现了空指针异常,但别人可能不清楚这个空指针是如何产生的,这时即可自定义一个显示具体信息的异常,比如自定义一个用户信息为空时抛出的异常: NullOfUserInfoException, 当这个异常发生就代表用户填写的信息不完整

(2)程序中有些错误是符合Java语法的,但不符合业务逻辑或者实际情况,比如程序中出现了一个人的年龄是负数、人员个数为小数等。

(3)在分层的软件架构中,通常在表现层统一对系统其他层次的异常进行捕获处理。

8.6  异常的使用原则

        Java异常强制用户去考虑程序的强健性和安全性。异常处理不应该用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应的处理。编写代码处理某个方法可能出现的异常时,可遵循以下原则。

( 1)不要过度使用异常。虽然通过异常可以增强程序的健壮性,但如果使用过多不必要的异常处理,可能会影响程序的执行效率。

(2)不要使用过于庞大的try..catch块。在一个try块中放置大量的代码,这种写法看上去“很简单”,但是由于try块中的代码过于庞大,业务过于复杂,会造成try块中出现异常的可能性大大增加,从而导致分析异常原因的难度也大大增加。

(3)避免使用catch(Exceptione)。因为如果所有异常都采用相同的处理方式,将导致无法对不同异常分情况处理;另外,这种捕获方式可能将程序中的全部错误、异常捕获到,这时如果出现一些“关键”异常,可能会被“悄悄地”忽略掉。

(4)不要忽略捕捉到的异常,遇到异常一 定要及时处理。

(5)如果父类抛出多个异常,则覆盖方法必须抛出相同的异常或其异常的子类,不能抛出新异常。

8.7  小结

        本章向读者介绍的是Java中的异常处理机制。通过本章的学习读者应了解异常的概念,几种常时异常类, 掌握异常处理技术,以及如何创建、激活用户自定义的异常处理器。Java中的异常处定通过ty..tcho语向来实现的,也可以使用throws语句向上抛出。建议读者不要随意将异常抛凡是由 自身引起的异常,都要积极处理:若不是自身引起的异常,则及时交给上层代码来处理。5异常处理的使用原则,读者也应该理解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值