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,否则表示编译错误。