异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)。
Java把异常当作对象来处理,并定义一个基类java.lang.Throwable
作为所有异常的超类,有两个子类Error和Exception
,分别表示错误和异常。
Java程序在执行过程中所发生的异常事件可分为两类:
java中的Exception类的子类不仅仅只是像上图所示只包含IOException和RuntimeException这两大类,Exception的子类很多很多,主要可概括为运行时异常(RuntimeException)
和非运行时异常
,也称为不检查异常(Unchecked Exception)
和检查异常(Checked Exception)
。
NullPointerException、IndexOutOfBoundsException
等, 这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。IOException、SQLException
等以及用户自定义的Exception异常,一般情况下不自定义检查异常。Java提供的是异常处理的抓抛模型。
Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出
由开发人员手动创建:Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样
若执行try块的过程中没有发生异常,则跳过catch子句。若是出现异常,try块中剩余语句不再执行。开始逐步检查catch块,判断catch块的异常类实例是否是捕获的异常类型。匹配后执行相应的catch块中的代码。
如果异常没有在当前的方法中被捕获,就会被传递给该方法的调用者。如果异常没有在调用者方法中处理,它继续被抛给这个调用方法的上层方法。这个过程一直重复,直到异常被捕获或被传给main方法(交给JVM来捕获),这一过程称为捕获(catch)异常。
如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。
程序员通常只能处理Exception,而对Error无能为力。
异常处理是通过try-catch-finally语句实现的。
try{
...... //可能产生异常的代码
}
catch( ExceptionName1 e ){
...... //当产生ExceptionName1型异常时的处置措施
}
catch( ExceptionName2 e ){
...... //当产生ExceptionName2型异常时的处置措施
}
[ finally{
...... //无论是否发生异常, 都无条件执行的语句
} ]
try
捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。
catch( Exception e)
在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句。对于try里面发生的异常,他会根据发生的异常和catch里面的进行匹配(按照catch块从上往下匹配),如果有匹配的catch,它就会忽略掉这个catch后面所有的catch。
在catch中可以捕获异常的有关信息:
finally
不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否有异常,catch语句中是否有return,finally块中的语句都会被执行;
finally中的return、throw会覆盖try、catch中的return、throw;
finally语句和catch语句是任选的。
public int test() {
try {
int a = 1;
a = a / 0;
return a;
} catch (Exception e) {
return -1;
} finally{
return -2;
}
}
// 方法返回值:-2
当执行代码a = a / 0;
时发生异常,try块中它之后的代码便不再执行,而是直接执行catch中代码;在catch块中,当在执行return -1
前,先会执行finally块;由于finally块中有return语句,因此catch中的return将会被覆盖,直接执行fianlly中的return -2
后程序结束。因此输出结果是-2。
注意
throws关键字用于方法体外部的方法声明部分,用来声明方法可能会抛出某些异常类型,也可以是它的父类。仅当抛出了检查异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出。
import java.io.*;
public class ThrowsTest {
public static void main(String[] args) {
ThrowsTest t = new ThrowsTest();
try {
t.readFile();
} catch (IOException e) {
e.printStackTrace();
}
}
public void readFile() throws IOException {
FileInputStream in = new FileInputStream("data.txt");
int b;
while ((b=in.read()) != -1) {
System.out.print((char) b);
}
in.close();
}
}
重写方法不能抛出比被重写方法范围更大的异常类型 (<=)。在多态的情况下,对methodA()方法的调用-异常的捕获按父类声明的异常处理。
public class A {
public void methodA() throws IOException {
……
}
}
public class B1 extends A {
public void methodA() throws FileNotFoundException {
……
}
}
public class B2 extends A {
public void methodA() throws Exception { // 报错
……
}
}
throw关键字是用于方法体内部,用来抛出一个Throwable类型或其子类的异常。
如果抛出了检查异常,则还应该在方法头部声明方法可能抛出的异常类型。该方法的调用者也必须检查处理抛出的异常。如果所有方法都层层上抛获取的异常,最终JVM会进行处理,处理也很简单,就是打印异常消息和堆栈信息。
public static void test() throws Exception
{
throw new Exception("方法test中的Exception");
}
一般地,用户自定义异常类都是RuntimeException的子类。
语法:
// 1.定义异常类
class 自定义异常类 extends 异常类型(Exception) {
// 2.重载构造方法
// 3.将异常信息传递给父类:super(...)
}
示例:
// 备注: 这些方法怎么来的? 重写父类Exception的方法
public class CustomException extends Exception {
static final long serialVersionUID = 13465653435L;
//无参构造方法
public CustomException(){
super();
}
//有参的构造方法
public CustomException(String message){
super(message);
}
// 用指定的详细信息和原因构造一个新的异常
public CustomException(String message, Throwable cause){
super(message,cause);
}
//用指定原因构造一个新的异常
public CustomException(Throwable cause) {
super(cause);
}
}
捕获异常:
抛出异常:
声明异常:
原文:https://www.cnblogs.com/itzlg/p/12037057.html