Java笔记----第十章(X) 异常处理

一、Java中的异常

1.含义

Java中的异常,指不期而至的各种状况,如:文件找不到网络连接失败非法参数等。异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程。
例如:遇到除数为0时,或者不是整数类型的数据时,运行就会报错(此案例将会在下面讲解)。

二、异常类

1.异常类结构图
Object
Throwable
Error
Exception
RuntimeException
Non-RuntimeException
各种运行异常子类
各种非运行异常子类
各种错误子类

注:
1. Java通过API中“Throwable类的众多子类”,来描述各种不同的异常。因而,Java的异常都是对象,是Throwable子类的实例,描述了出现在一段编码中的错误条件。当条件成立时,错误将引发为异常。
2. Throwable有两个子类:Exception(异常)类Error(错误)类。(Java程序用继承的方式来组织各种异常。所有的异常都是Throwable类或其子类,而Throwable类又直接继承于Object类。

2.运行时异常与非运行时异常

运行时异常: 都是RuntimeException类及其子类异常,如NullPointerExceotion、IndexOutOfBoundsException等,这些异常是不检查异常,程序可以选择捕获处理,也可以不处理。
非运行时异常: 是RuntimeException以外的异常,类型上都属于Exception类及其子类。如IOException、SQLException等以及用户自定义的Exception异常。

3.Java中的异常类
(1)Exception类及其子类

可以被捕获并且可能恢复的异常类,用户程序也可以通过继承Exception类,来生成自己的异常类。常见的Exception异常类如下:
1) java.awt.AWTException , 抽象窗口工具包AWT出现异常;
2) java.nio.channels.AlreadyBoundException , 尝试绑定已经绑定的、网络套接字时抛出的异常;
3) java.util,zip.DataFormatException , 数据格式错误异常;
4) java.io.FileNotFoundException , 试图打开一个指定路径的文件时,引发的异常。当指定路径的文件不存在,而使用FileInputStream , FileOutputStream或RandomAccessFile构造案例时,就会抛出这个异常;如果这个文件确实存在,但因为某些特殊原因(如:打开一个只读文件进行读写时)也会抛出这个异常。
5) java.net,HttpRetryException , 当流媒体模式被启动,一个HTTP请求需要重新发送,却无法自动重发而引发的异常。
7) java.net.MalformedURLException , 统一资源定位器(URL)的格式不正确,引发的异常。
8) java.net.ProtocolException ,网络协议异常;
9) java.net,SocketException , Socket 操作异常;
10) java.lang.ArithmeticException , 算术(如除数为0)运算时引发的异常;
11)) java.lang.ClassCastException , 类型转换异常;
12) java.lang.IndexOutOfBoundsException , 下标越界异常;
13) java.lang.NullPointerException , 访问一下空对象中的成员时引发的异常;
14) java.lang.NumberFormatException , 数据类型转换错误的异常;
15) java.util.InputMismatchException , 通过Scanner对象输入的数据类型,与接收数据的类型不匹配而引发的异常;
16) java.lang.ArrayIndexOutOfBoundsException , 数组下标越界异常,如定义 int a[ ] = new int[3] ; 引用 int a[3] = {1,2,3} , 引发其中的元素a [3],其中a[3]为第四个元素,因为Java数组引用下标是从0开始,a[0]是第一个元素,类推后a[3]是第四个元素。

(2)Error类及其子类

一般情况下,被认为是不可恢复,和不可捕捉的异常类,用户程序不需要处理这类异常。
在捕捉Error类及子类时要多加小心,因为他们通常是出现灾难性错误时被创建,常见的Error异常类如下:
1) java.lang.LinkingeError,一个类A依赖于另一个类B,当类A编译完成后,类B发生了更改,导致A无法找到B,而创建的错误信息对象。
2) java.lang.VirtualMachineError , java虚拟机坏了,或继续运行java虚拟机,所需资源已经耗尽了,而创建的错误信息对象;
3) java.awt . AWTError , 抽象窗口工具包,AWT发生严重错误时而创建的错误信息对象。

三、异常处理的方法

1.使用try…catch结构捕获异常

在try代码块中编写:可能发生的异常;在catch代码块中:捕获执行这段代码时可能发生的异常。
格式如下:

try{
    
    
    可能产生异常的代码;
}catch(异常类 异常对象){
    
    
    异常处理代码;
}

注:
1. try代码块中的代码,可能同时存在多个异常。
2. catch代码块中的“异常类”参数,指定要捕获哪些参数。

public class AgeStr2Int {
    
    

	public static void main(String[] args) {
    
    
		try {
    
    
			int age = Integer.parseInt("19A");  //可能抛出NumberFormatException异常
			System.out.println("年龄为:"+age); //1
		}catch(NumberFormatException ex){
    
      //捕捉NumberFormatException异常
			System.out.println("年龄信息必须为整数类型。"); //1
			ex.printStackTrace(); //2
		}
	}
}
2.多重catch代码块的用法

多个catch代码块格式如下:

try{
    
    
    可能产生异常的代码;
}catch(异常类1 异常对象1){
    
    
    异常1处理代码;
}catch(异常类2 异常对象2){
    
    
    异常2处理代码;
}
...其它的catch语句块
}catch(异常类n 异常对象n){
    
    
    异常n处理代码;
}

例:

public class DivByZeroUseMultiCatch {
    
    

	public static void main(String[] args) {
    
    
		Scanner input = new Scanner(System.in);
		int x, y;
		System.out.println("请输入一个除数x:");
		try {
    
    
			x = input.nextInt();
			y = 10 / x; 
			System.out.println("10/x的结果为:" + y);
		} catch (InputMismatchException ex) {
    
    
			System.out.println("输入的除数数据必须是整数类型!");
		} catch (ArithmeticException ex) {
    
    
			System.out.println("除数不能为0!");
		} catch (Exception ex) {
    
    
			System.out.println("其它未知的错误!");
		}
		input.close();
	}
}

3.finally类子句的用法

使用了finally子句后,不管程序中有异常发生,也不管之前的try…catch结构是否顺利执行完毕,最终都会执行finally代码块中的代码,这使用一些不管在任何情况下,都必须执行的步骤被执行,从而保证了程序的健壮性。

例:

public class DivByZeroUseFinally {
    
    

	public static void main(String[] args) {
    
    
		Scanner input = new Scanner(System.in);
		int x, y;
		System.out.println("请输入除数x:");
		try {
    
    
			x = input.nextInt();
			y = 10 / x;
			System.out.println("10/x的结果为:" + y);
		} catch (InputMismatchException ex) {
    
    
			System.out.println("输入的除数数据必须是整数类型!");
		} catch (ArithmeticException ex) {
    
    
			System.out.println("除数不能为0!");
		} catch (Exception ex) {
    
    
			System.out.println("其它未知的错误!");
		} finally {
    
    
			System.out.println("欢迎使用本计算机程序!");
		}
		input.close();
	}
}
4.使用throws关键字抛出异常

如果某个方法会抛出异常,但不想在当前的这个方法中来处理这个异常,可以将这个异常抛出,在调用这个方法的代码中,捕捉这个并进行处理。Java语言通过关键字throws,声明某个方法可能抛出的多个异常,throws可以同时声明多个异常,各个异常之间用逗号分隔。

5.使用throw关键字抛出异常

使用try…catch结构与throw关键字,抛出与捕获都是系统定义的异常。Java提供了一个throw关键字,可以在方法体内部抛出一个异常类对象。如:性别只存在“男”和“女”,这些都是系统难发现的异常。

注意: throws和throw有如下几点不同,使用时要特别注意:
1)作用不同:throw用于Java语言环境不能捕获的异常。如年龄、性别等逻辑错误,由程序员自行产生并抛出;throws用于声明在该方法内部抛出了异常。
2)使用的位置不同:throw位于方法体内部,可以作为单独的语句使用;throws必须跟在方法参数列表的后面,不能单独使用。
3)内容不同:throw抛出一个异常对象,而且只能抛出一个;throws后面跟异常类,而且可以跟多个异常类。

6.使用异常处理语句的注意事项

进行异常处理时,主要使用了trycatchfinallythrowstthrow等关键字,在使用它们时,需注意以下几点:
1) 对于程序中的异常,必须使用try…catch结构捕获,或通过throws向上抛出异常,否则编译会报错。
2) 不能单独使用try、catch或者finally代码块,否则代码在编译时会报错。
3) try代码块后面,可以单独的跟一个到多个catch代码块,也可以单独的仅跟一个finally代码块,catch代码块和finally代码块可以同时存在,但finally代码块一定要跟在catch代码块之后。

格式如下:
try{
    
    
    //try块的代码
}catch(异常类型 异常变量){
    
    
   //一个或多个catch块
}finally{
    
    
   //最多只能有一个finally块
   //不管是否有异常抛出或捕获,finally代码块都会被执行
}

4) 在try…catch…finally结构中,不论程序是否会抛出异常,finally代码块都会被执行。
5) try只能跟catch代码配合使用时,可以使用多个catch块,来捕获try代码块中可能发生的多种异常。异常发生后,Java虚拟机会由上而下的检查当前catch代码块中所捕获的异常,是否与try代码中发生的异常匹配,若匹配,则不再执行其它的catch代码块。
如果多重catch代码块捕获的是同种类型的异常,则捕获子类异常的catch代码块要放在捕获父类异常的catch块代码之前,否则将会在编译时发生编译错误。

//格式如下:
try {
    
      //try中的代码
}catch(NumberFormatException ex){
    
     //数据格式化异常
       //异常1
} catch (IIIegalArgumentException ex) {
    
     //非法参数异常
	  //异常2,NumberFormatException是IIIegalArgumentException的子类
} catch (RuntimeException ex) {
    
     //运行时异常
	 //异常3,IIIegalArgumentException是RuntimeException的子类
} catch (Exception ex) {
    
     
    //异常4,RuntimeException是Exception的子类
}

6) 在try、catch、finally等的代码块中,定义的变量为局部变量,只能在代码块内部使用,如果要使用全局变量,则要将变量定义在这几个模块之外;
7) 在使用throw语句,抛出一个异常对象时,该语句后面的代码将不会被执行。

//例:
  if(age<0){
    
     //如果年龄小于0
   throw new Exception("年龄不能为负数!");//1抛出一个异常
}
return age;  //2

解析: 在程序运行过程中,当年龄小于0时,会使用1处的代码行抛出异常,并中断该段程序的执行,因此此时代码行2将不能执行。

四、自定义异常

1.案例

自定义异常,必须是继承自Throwable类或其子类,才能被视为异常类,在实现中通常继承Exception类或其子类。(自定义类的使用方法与Java语言内置的异常类的使用方法相同。)

例:

//自定义异常类
public class MyStrChkException extends Exception{
    
    

	private static final long serialVersionUID = 1L;

	private String content;

	public MyStrChkException(String content) {
    
    
		this.content = content;
	}

	public String getContent() {
    
    
		return content;
	}
}

//测试类
public class MyStrChkTest {
    
    
/**检查字符串是否含有非法字符的方法
 * @param str 要检查的字符串
 * @throws MyStrChkException 抛出自定义的异常*/
    public static void chkStr(String str) throws MyStrChkException{
    
    
    	char[] array = str.toCharArray();
		int len = array.length;
    	for(int i=0;i<len-1;i++) {
    
    
    		//数字0~9的ASSIC码值为48.57,大写字母A~Z的ASSIC码值为65~90
    	    //小写字母的ASSIC码值为97-122
    		if(!((array[i]>=48 && array[i]<=57) ||(array[i]>=65 && array[i]<=90) ||(array[i]>=97 && array[i]<=122))) {
    
    
    	       throw new MyStrChkException("字符串:"+str+"中含有非法字符。");
    	}
    }
	
}	
	public static void main(String[] args) {
    
    
		String str1 = "abczA09Z";
		String str2 = "ab!334@";
		try {
    
      chkStr(str1);
		System.out.println("字符串1为:"+str1);
		chkStr(str2);
		System.out.println("字符串1为:"+str2);
		}catch(MyStrChkException ex) {
    
    
			System.out.println("触发自定义的异常,异常内容如下:");
			System.out.println(ex.getContent());
		}
	}
}
 
运行结果:
字符串1为:abczA09Z
触发自定义的异常,异常内容如下:
字符串:ab!334@中含有非法字符。

五、综合案例

1.问题

一般程序中遇到除数为0的情况时,或者不是整数类型的数据时,运行就会出错,此时该如何解决呢?

2.解决方案

方案1:利用if…else改进代码!

面对除数为0的这种情况,我们需要做如下修改:

```java
public class DivByZeroUseMultiCatch {
    
    

	public static void main(String[] args) {
    
    
	
		Scanner input = new Scanner(System.in);//输入对象
		int x, y;
		System.out.println("请输入一个除数x:");
		if(input.hasNextInt()){
    
     //判断是否为整数
           x = input.hasNextInt();
           if(x==0){
    
    
              System.out.println("除数是0,运算结果为无穷大。")
           }else{
    
    
               y = 10/x;
               System.out.println("10/x的结果为:"+y);
        }else{
    
    
               System.out.println("您输入的数据不是整数类型。");
        }
		input.close();
	}
}

缺陷:
使用 if…else语句使得程序的复杂度增加,编程时出错率也大大升高,在代码量增加的前提下,也增加了修改和维护的难度,降低了开发的效率。所以还需要改进代码。

方案2:使用try…catch代码块改进代码!---->达到理想的效果!

public class DivByZeroUseFinally {
    
    

	public static void main(String[] args) {
    
    
		Scanner input = new Scanner(System.in);
		int x, y;
		System.out.println("请输入除数x:");
		try {
    
    
			x = input.nextInt();
			y = 10 / x;
			System.out.println("10/x的结果为:" + y);
		} catch (InputMismatchException ex) {
    
    
			System.out.println("输入的除数数据必须是整数类型!");
		} catch (ArithmeticException ex) {
    
    
			System.out.println("除数不能为0!");
		} catch (Exception ex) {
    
    
			System.out.println("其它未知的错误!");
		}
		input.close();
	}

}

.

猜你喜欢

转载自blog.csdn.net/qq_46340895/article/details/105501871
今日推荐