前言
本章内容将会介绍Java的异常处理 机制,包括异常的基本概念,基本异常的分类,异常的处理方法等等。之后拓展一下Error和Runtime Exception.
一、异常的基本概念
在程序运行时打断正常程序流程的任何不正常的情况称为错误或异常。Java的异常处理是面向对象的,也就是可以将异常当做对象来处理。当程序运行过程中出现了异常情况时,一个异常就产生了并交给运行时系统,运行时系统通过寻找对应的代码来处理这个异常,从而保证系统不会宕机或对操作系统造成伤害。
二、异常的分类
1.编译时异常
在代码编译时发生的错误
public class Person {
private String name;
private String gender;
int age;
@Override
public Person clone(){
return (Person)super.clone();
}
}
对于这类异常编译器会强制用户处理,否则会导致编译不通过。这些异常一般都需要进行捕获或者强制声明抛出。
2.运行时异常
在程序执行期间发生的错误
三、异常的处理
Java提供了5个关键字来处理异常try,catch,finally,throw,throws。一般try-catch-finally会配套使用,用来捕获异常 ,throw用来抛出异常,throws用来声明抛出异常。在异常捕获中,try是必须存在的,catch和fianlly可以同时存在且必须至少存在一个。try用于包裹需要进行异常处理的代码块,catch则用于捕获异常并根据需要进行特殊处理,finally语句是资源保护块,无论是否产生异常或者异常是否被捕获,该语句块都会执行。
try-catch-finally语句的基本格式如下:
try{
//一条或多条可能抛出异常的Java语句
}catch(异常类型 异常对象){
//异常处理
}catch(异常类型 异常对象){
//异常处理
}finally{
//特殊处理代码块
}
异常的捕获顺序是向下的,也就是说,异常发生时,不活代码会默认从最近的一场开始匹配,一旦匹配上了就结束匹配,执行该异常的异常处理代码。所以在catch异常的时候需要将更具体的一场最先进行捕获处理,否则,可能被其父类异常捕获 而导致无法处理。
对于可能会抛出异常的代码块,调用者既可以使用捕获的方式进行处理,也可以将异常抛出。Java中异常抛出使用的是throw关键字;对于声明抛出异常,则使用throws来标识。抛出的异常,可以使Java提供的标准异常,也可以是用户自定义的异常。抛出异常的一般形式是:
throw 异常对象;
或者
throws new 异常名称();
两种形式本质上是一样的,因第一种需要先构造异常对象,所以一般使用后者。throw语句一旦被执行,程序立即转入相应的异常处理程序段,其后的语句将不再执行。
采用try-catch语句进行异常处理实例:
public class TextDemo {
public static void main(String[] args) {
int i = 0;
String greetings[] = {"Hello World!", "Hello!", "HELLO BIT!"};
while (i < 4) {
try {
//一条或多条可能抛出异常的Java语句
System.out. println(greetings[i]);
i++;
} catch (ArrayIndexOutOfBoundsException e) {
//异常处理
// }catch(异常类型 异常对象){
// //异常处理
// }finally{
//特殊处理代码块
}
}
}
}
异常的抛出:
public class ThrowDemo {
public void getString(String str)throws Exception{
try{
System.out.println("getString-传入的对象是,str="+str.toLowerCase());
}catch(NullPointerException e){
throw e;
}
}
//自己处理异常
public void getString2(String str){
try{
System.out.println("getString2-传入的对象是,str="+str.toLowerCase());
}catch(NullPointerException e){
System.out.println("getString2-传入的字符串是空值,自行处理");
}
}
public static void main(String[] args) {
ThrowDemo td=new ThrowDemo();
String str="Not Null";
String strNull=null;
//自行处理异常,没有抛出,无需进行异常捕获
td.getString2(strNull);
td.getString2(str);
//会强制用户处理该方法声明抛出的异常
try{
td.getString(strNull);
}catch(Exception e){
e.printStackTrace();
}
//会强制用户处理该方法声明抛出的异常
try{
td.getString(strNull);
}catch(Exception e){
e.printStackTrace();
}
System.out.println("程序运行结束!");
}
}
四、自定义异常
Java虽然提供了很多的标准异常,但实际的程序开发中这些标准异常并不能覆盖所有的场景,此时就需要定义一些异常来处理与业务相关的一些场景。
例如,有一个异常检查,要求传入的整形类型的数据不能超过100,否则就抛出异常。
public class TestSelfException {
//如果传入的整形参数大于100,则抛出自定义异常
public void getNum(int i)throws Exception{
if(i>100){
throw new Exception("整形参数不能大于100!");
}else{
System.out.println("传入的参数是:"+i);
}
}
public static void main(String[] args) {
TestSelfException tse=new TestSelfException();
int num=99;
try{
tse.getNum(num);
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("num="+num);
num=101;
}
//调用方法,闯入101,抛出异常
try{
tse.getNum(num);
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("num="+num);
}
}
}
五、Error和Runtime Exception.
Error 指错误,这些错误一般是程序无法处理的且可能会导致程序异常终止的问题。这类问题大部分是与JVM相关,或者与系统有关的,- 一般是应该在系统级别上被捕获的异常,程序本身般无法处理。 这类问题般是系统错误或底层资源的错误。这些错误会导致程序的运行被终止。
Error的子类有: IOError、IntemalError、ThreadDeath和VirtualMachineError等,Error的直接父类是Throwable。
RuntimeException是Exception下不受检查的异常类型,在一个方法中抛出RuntimeException或其子类,方法可以不进行捕获且无需声明抛出。其子类常用的有NullPointException 、SystemException 、ParseException 和ClassCastException等。不受检查的异常因为不需要进行强制捕获或者声明抛出,减少了代码的书写,但是,因为少了强制检查,在一-些重要的场景下没有处理可能会导致程序产生运行事故等。所以,一般情况下, 自定义异常不要使RuntimeException类或者其子类作为父类。