异常

129 阅读6分钟

Java异常处理笔记记录

异常

程序运行过程中会出现各种错误,常见的错误包如除数为零、数组下标越界、文件找不到、内存溢出、栈溢出等。 通常有两种处理方法: 1、计算机系统本身直接检测程序错误,遇到错误时程序终止运行 2、程序员设计过程中兼顾错误检测、错误信息显示、出错处理 Java提供异常处理机制来处理程序运行中的错误, Java系统中专门设置了一个调用栈,此栈中装有指向异常处理方法的指针

异常引起的原因

1、程序中存在非法操作,程序员考虑不周导致,称为隐式异常。 2、程序中使用throw语句引起的异常,是有意安排的,称为显式异常。

异常类

异常类层次结构

在这里插入图片描述Throwable是所有异常类的超类

Error(错误)(非检查异常)

程序员无法处理的问题,例如:内存溢出(OutOfMemoryError),JVM错误(Virtual MachineError),栈溢出(StackOverflowError),类定义错误(NoClassDefFoundError)。此类错误与程序本身无关,通常由系统进行处理。

Exception(异常)

RuntimeException(运行时异常)(非检查异常)

是Exception的子类,是由于程序逻辑错误引起的,例如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,程序由字节码程序(.class后缀)经解释器运行到操作系统时产生的。

除RuntimeException之外的Exception的其他子类(编译时异常)(非运行时异常)(检查异常)

编译器会检查,源程序(.java后缀)编译到字节码文件(.class后缀)的过程,此类异常必须处理,否则编译不通过。

异常处理

异常处理可通过5个关键字实现控制: try、catch、finally、throw、throws

try-catch-finally语句

try --- 用于监听。放置异常监控的程序段,不能单独使用,必须和catch/finally子句配合使用。 catch – 用于捕获异常。catch用来捕获try语句块中发生的异常。catch语句可以有多个, finally – 无论如何一定都会执行的语句。常用于回收资源。 finally 遇到如下情况时无法正常执行: 1、前面的代码中用了System.exit()退出程序。 2、finally语句块中发生了异常。 3、程序所在的线程死亡。 4、 关闭CPU。

public class ExceptionTest {

	public static void main(String[] args) {
		int i=0;
		String[] str= {"one","two","three"};
		try{
			while(i<=3) {
		
			System.out.println(str[i]);
			i++;
		}
		}catch(java.lang.ArrayIndexOutOfBoundsException e) {//e就是抛出的相应的异常类对象
			System.out.println("数组下标越界异常");
		}finally {
			System.out.println("finally i="+i);
		}
		System.out.println("程序正常结束");
	}
}

try-catch-finally语句的作用:当try语句块中的代码执行发生异常,程序正常运行被中断,并抛出异常对象,然后在try块后面的各个catch()中找出与异常对象相匹配的类。 异常对象与对应异常类相匹配的条件: 1、异常对象所属类与catch()中的参数类相同; 2、异常对象所属类是catch()中的参数类的子类; 3、catch()中参数类是一个接口时,发生的异常对象类实现了这一接口。

  • 1、找到第一个与之匹配的参数类时,就执行这个catch()语句,即异常处理,,处理完之后,程序恢复运行,但不会回到异常发生处继续执行,而是执行try-catch结构后面的代码。
  • 2、有多个catch子句时,最多只会执行其中一个catch语句块中的异常处理代码,若处理的多个异常之间存在继承关系,则先处理其子类异常,即处理子类异常的catch子句要放在前面,否则编译不能通过。 实例:
public class CatchException {
	public static void main(String[] args) {
		int a,b,c;
		a=110;
		b=0;
		try {
			c=a/b;
			System.out.println(a+"/"+b+"="+c);
		}catch(ArithmeticException e) {
			System.out.println("出现被0除的异常情况");
		}catch(Exception e) {
			System.out.println("异常类型为:"+e);
		}finally{
			System.out.println("除数="+a);
			System.out.println("被除数="+b);
		}
		a=110;
		b=10;
		try {
			c=a/b;
			System.out.println(a+"/"+b+"="+c);
		}catch(ArithmeticException e) {
			System.out.println("出现被0除的异常情况");
		}catch(Exception e) {
			System.out.println("异常类型为:"+e);
		}finally{
			System.out.println("除数="+a);
			System.out.println("被除数="+b);
		}
	}
}

throw(异常的抛出)

程序中存在非法操作,会导致异常发生(隐式异常);在程序中也可以使用throw语句人为抛出异常(显式异常)。 如果代码可能引发某种错误,可使用throw语句抛出异常。 throw语句抛出异常有两种方法: 1、直接抛出异常类实例

throw new ExceptionType(...)//ExceptionType是Throwable类的子类

2、先定义异常类对象并实例化,然后抛出

ExceptionType e=new ExceptionType(...);
throw e;

实例:

public class ThrowException {

	public static void main(String[] args) {
		int age=200;
		try {
			if(age<0||age>120)
				throw new Exception("年龄数据超出范围");
			System.out.println("age="+age);
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

}

一个方法中抛出的异常,该方法可以处理也可以不处理,而是把异常向上传递,递交给调用该方法的方法来处理。若在方法中不处理抛出的隐式异常,该异常隐性传递给调用该方法的方法,即默认异常处理方式;若在方法中不处理抛出的显式异常,则必须在定义该方法时使用throws子句作为异常显式抛弃声明,否则编译不通过。

throws(异常的申明)

Java中执行的语句一定属于某个方法,Java解释器调用main()执行程序,若方法中存在检查异常,如果不对其进行捕获,那必须在方法头中显式声明异常。

  • 注意:父类方法没有声明异常,则子类继承后,也不能声明异常。
  • 如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。
  • 必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误 仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出。
  • 调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

public class ThrowException {
	public static int calc(int x) {
		int z=0;
		z=110/x;
		return z;
		
	}

	public static void main(String[] args) {
		int a=0;
		try {
			a=calc(0);
			System.out.println("a="+a);
		}catch(ArithmeticException e) {
			System.out.println("调用方法calc时发生异常"+e.getMessage());
			e.printStackTrace();
		}
	}

}
//程序执行到主方法的语句:a=calc(0)时发生异常,该异常是方法在z=110/x产生的,是隐性式异常,可以不用throws语句声明,声明也可以

	public static int calc(int x) throws Exception {
		int z=0;
		if(x==0)
			throw new Exception("除数为零1");
		z=110/x;
		return z;
		
	}

	public static void main(String[] args) throws Exception {
		int a=0;
		try {
			a=calc(0);
			System.out.println("a="+a);
		}catch(Exception e) {
			System.out.println("调用方法calc时发生异常:"+e.getMessage());
			e.printStackTrace();
		}
	}

}//由于方法calc中使用显式抛出异常语句throw,所以在calc()方法头中必须增加throws Exception 子句声明抛出异常,否则编译不能通过。

自定义异常类

除了可以使用Java包中预定义的异常类,Java还允许自定义异常类来处理特殊情况。用户自定义异常类主要用来处理用户程序中特定的逻辑运行错误。 自定义异常类一般都是以Exception类为父类。 自定义异常类对象只能用throw语句抛出。 习惯上,定义一个异常类应包含两个构造函数,一个无参构造函数和一个带有详细描述信息的构造函数。

import java.util.Scanner;

public class DefineException {

	public static void main(String[] args) {
		final int MIN=25,MAX=40;
		Scanner scan=new Scanner(System.in);
		OutOfRangException problem=new OutOfRangException();
		System.out.println("输入"+MIN+"到"+MAX+"之间的整数");
		try {
			int value=scan.nextInt();
			if(value<MIN||value>MAX)
				throw problem;
			
		}catch(OutOfRangException e) {
			System.out.println(e.toString());
		}
		System.out.println("主方法结束");
		
	}

}
//定义一个异常类,类名为OutOfRangException
class OutOfRangException extends Exception{
	OutOfRangException(){
		super("输入数据超出范围");
	}
}
//运行该程序时,主方法读入一个整数,检测该数据是否在有效值范围内,如果超出有效值范围,将执行throw语句抛出一个用户自定义异常。在主方法中使用throw语句显式抛出异常,如果不使用try-catch-finally语句捕获和处理,则必须在主方法中说明异常抛出声明:throws  OutOfRangException,否则表示编译错误。