欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

异常的捕获及处理

程序员文章站 2022-04-01 11:31:59
...

异常的捕获及处理

认识异常

异常是导致程序中断执行的一种指令流,一旦产生异常没有正常处理的话,那么程序江湖中断执行。
范例:观察产生异常的代码

public class Hello{
	public static void main(String args[]){
		System.out.println("AAAAAA  计算开始  AAAAAA");
		System.out.println("BBBBBB  除法计算:"+(10/0)+"  BBBBBB");
		System.out.println("CCCCCC  计算结束  CCCCCC");
	}
}

异常的捕获及处理
出现异常,程序并未执行完,而是打印了一条信息。

处理异常

如果要在Java中进行异常的处理可以使用三个关键字的组合完成:try、catch、finally。有如下语法:
异常的捕获及处理
而此时给出的语法也有三种组合模式:try…catch、try…catch…finally、try…finally。
范例:实现异常的处理操作

public class Hello{
	public static void main(String args[]){
		System.out.println("AAAAAA  计算开始  AAAAAA");
		try{
			System.out.println("BBBBBB  除法计算:"+(10/0)+"  BBBBBB");
		}catch(ArithmeticException e){//e是一个对象
			System.out.println(e);
		}
		System.out.println("CCCCCC  计算结束  CCCCCC");
	}
}

异常的捕获及处理
此时程序出现异常仍可以正常执行完毕。
要想完整的输出异常信息,则可以使用printStackTrace()方法完成。

public class Hello{
	public static void main(String args[]){
		System.out.println("AAAAAA  计算开始  AAAAAA");
		try{
			System.out.println("BBBBBB  除法计算:"+(10/0)+"  BBBBBB");
		}catch(ArithmeticException e){//e是一个对象
			e.printStackTrace();
		}
		System.out.println("CCCCCC  计算结束  CCCCCC");
	}
}

异常的捕获及处理
范例:使用try…catch…finally来处理异常

public class Hello{
	public static void main(String args[]){
		System.out.println("AAAAAA  计算开始  AAAAAA");
		try{
			System.out.println("BBBBBB  除法计算:"+(10/0)+"  BBBBBB");
		}catch(ArithmeticException e){//e是一个对象
			e.printStackTrace();
		}finally{
			System.out.println("*************************");
		}
		System.out.println("CCCCCC  计算结束  CCCCCC");
	}
}

异常的捕获及处理
异常产生之后找到了相应的catch语句执行,而后处理异常完毕后继续执行finally的代码。

public class Hello{
	public static void main(String args[]){
		System.out.println("AAAAAA  计算开始  AAAAAA");
		try{
			System.out.println("BBBBBB  除法计算:"+(10/2)+"  BBBBBB");
		}catch(ArithmeticException e){//e是一个对象
			e.printStackTrace();
		}finally{
			System.out.println("*************************");
		}
		System.out.println("CCCCCC  计算结束  CCCCCC");
	}
}

异常的捕获及处理

多个异常的处理

在一个try语句之后可以编写多个catch进行处理,模拟一个输入的数字计算操作,假设要计算的数字使用过初始化参数设置的。
范例:修改程序代码

public class Hello{
	public static void main(String args[]){
		System.out.println("AAAAAA  计算开始  AAAAAA");
		try{
			int x = Integer.parseInt(args[0]);
			int y = Integer.parseInt(args[1]);
			int result=x/y;
			System.out.println("BBBBBB  除法计算:"+result+"  BBBBBB");
		}catch(ArithmeticException e){//e是一个对象
			e.printStackTrace();
		}finally{
			System.out.println("*************************");
		}
		System.out.println("CCCCCC  计算结束  CCCCCC");
	}
}

下面就有了这样几种执行情况:

  • 执行程序没有设置初始化参数:ArrayIndexOutOfBoundsException;
  • 执行程序的时候输入的内容不是数字:NumberFormatException;
  • 执行的时候被除数为0:ArithmeticException。
    只有在异常处理之后,异常之后的代码才能执行,finally代码永远会出现。
    为了保证程序出现错误之后仍然可以正常执行完,可以采用多个catch。
    范例:修改代码,处理多个异常
 public class Hello{
    	public static void main(String args[]){
    		System.out.println("AAAAAA  计算开始  AAAAAA");
    		try{
    			int x = Integer.parseInt(args[0]);
    			int y = Integer.parseInt(args[1]);
    			int result=x/y;
    			System.out.println("BBBBBB  除法计算:"+result+"  BBBBBB");
    		}catch(ArithmeticException e){//e是一个对象
    			e.printStackTrace();
    		}catch(NumberFormatException e){//e是一个对象
    			e.printStackTrace();
    		}catch(ArrayIndexOutOfBoundsException e){//e是一个对象
    			e.printStackTrace();
    		}finally{
    			System.out.println("*************************");
    		}
    		System.out.println("CCCCCC  计算结束  CCCCCC");
    	}
    }

异常处理流程

两个异常类的继承结构

java.lang.ArithmeticException java.lang.NumberFormatException
异常的捕获及处理 异常的捕获及处理

可以发现所有的异常类都是java.lang.Throwable的子类,此类定义如下:

public class Throwable extends Object implements Serializable

可以发现Throwable直接是Object子类。从JDK1.0开始提供。但是在Throwable下有两个子类,因此在开发中几乎不会考虑Throwable处理。
面试题:请解释Throwable下的Error和Exception子类的区别。

  • Error:在程序还未执行时出现的错误,一般指的是JVM出错,用户无法处理;
  • Exception:在程序运行中出现的异常,异常处理都是针对此类型完成的。
    因此,以后开发之中异常处理的最大父类就是Exception。
  1. 当程序出现异常时会由JVM自动的根据异常类型实例化一个指定的异常类对象;
  2. 程序需要判断当前的代码之中是否存在有异常处理逻辑,如果没有,则由JVM默认处理,处理方式输出异常信息,而后中断程序执行。
  3. 如果程序中存在异常处理,则try语句会捕获该异常类的实例化对象(想象为引用传递)
  4. 捕获到的异常类的实例化对象要与catch中的异常类型进行依次匹配;
  5. 如果catch匹配了异常,则用相应的代码进行处理,随后执行finally语句,如果没有任何catch匹配,则交由finally进行处理。
  6. 执行完finally代码之后要判断该异常是否已经处理过,若处理过,则执行后续代码,若没有,则交由JVM进行默认处理。
    异常的捕获及处理
    catch匹配跟参数传递类似,实例化对象有类型匹配,则进行接收,所有的异常都可以由Exception处理。
    如果try语句后有多个异常处理,则大的异常处理要放在小的异常处理之后,否则出错。
    范例:利用Exception处理异常。
     public class Hello{
        	public static void main(String args[]){
        		System.out.println("AAAAAA  计算开始  AAAAAA");
        		try{
        			int x = Integer.parseInt(args[0]);
        			int y = Integer.parseInt(args[1]);
        			int result=x/y;
        			System.out.println("BBBBBB  除法计算:"+result+"  BBBBBB");
        		}catch(Exception e){//e是一个对象
        			e.printStackTrace();
        		}finally{
        			System.out.println("*************************");
        		}
        		System.out.println("CCCCCC  计算结束  CCCCCC");
        	}
        }      

在实际开发中如果有明确要求,就分开处理。其他情况采用Exception是最方便的。

throws关键字

用户如何知道那些代码会产生怎样的异常?Java中提供throws关键字,其主要目的是明确告诉用户执行某一个方法有可能会产生哪些异常。所以throws主要是用于方法的声明处。
范例:观察throws关键字的使用

class MyMath{
	public static int div(int x,int y)throws Exception{
		return x/y;
	}
}

表示如果想执行本语句就必须进行异常处理。
范例:不处理异常直接调用

class MyMath{
	public static int div(int x,int y)throws Exception{
		return x/y;
	}
}
public class Hello{
	public static void main(String args[]){
		System.out.println(MyMath.div(10, 2));
	}
}

异常的捕获及处理
代码中出现throws声明,表示必须强制性进行异常处理操作。
范例:正常调用形式

class MyMath{
	public static int div(int x,int y)throws Exception{
		return x/y;
	}
}
public class Hello{
	public static void main(String args[]){
		try{
			System.out.println(MyMath.div(10, 2));
		}catch(Exception e)	{
			e.printStackTrace();
		}
	}
}

但是使用了throws之后还有一个传递的问题,主方法也是一个方法,所以主方法也可以使用throws,那么就表示此时的主方法不进行异常的处理,而交给被调用处处理。

class MyMath{
	public static int div(int x,int y)throws Exception{
		return x/y;
	}
}
public class Hello{
	public static void main(String args[]) throws Exception{
		System.out.println(MyMath.div(10, 0));
	}
}

主方法之上就由JVM进行默认处理,一般主方法中应该把异常处理完成。

throw关键字

所有异常对象都是Java负责实例化,我们只能对异常进行捕获。Java中允许用户自己实例化异常对象,要抛出这个异常,就必须使用throw关键字。
范例:自己手工抛出异常

public class Hello{
	public static void main(String args[]) {//throws Exception
		throw new Exception("这是一个异常。");
	}
}

异常的捕获及处理
异常的捕获及处理
范例:异常处理

public class Hello{
	public static void main(String args[]) {//throws Exception
		try{
			throw new Exception("这是一个异常。");
		}catch(Exception e)	{
			e.printStackTrace();
		}
	}
}

异常的捕获及处理

异常处理的模型(核心)

设计除法计算方法,有如下要求:
异常的捕获及处理
范例:程序基本实现

class MyMath{
	public static int div(int x,int y)throws Exception{//交给被调用处处理
		int result=0;//保存计算结果
		System.out.println("************begin*************");
		result = x/y;
		System.out.println("*************end*************");
		return result;
	}
}
public class Hello{
	public static void main(String args[]) {//throws Exception
		try{
			System.out.println(MyMath.div(10, 2));
		}catch(Exception e)	{
			e.printStackTrace();
		}
	}
}

异常的捕获及处理
一旦程序出现错误,这个时候的运行结果如下。
异常的捕获及处理
范例:加入异常控制

    class MyMath{
	public static int div(int x,int y)throws Exception{//交给被调用处处理
		int result=0;//保存计算结果
		System.out.println("************begin*************");
		try{
			result = x/y;
		}catch(Exception e){
			throw e;//继续向上抛
		}finally{
			System.out.println("*************end*************");
		}
		return result;
	}
}
public class Hello{
	public static void main(String args[]) {//throws Exception
		try{
			System.out.println(MyMath.div(10, 0));
		}catch(Exception e)	{
			e.printStackTrace();
		}
	}
}

异常的捕获及处理
在以后的开发之中,一定会牵扯到资源的使用,例如文件、数据库操作前一定要打开,操作后一定要关闭。但是以上给出的异常处理模型可以简化:try…finally。

class MyMath{
	public static int div(int x,int y)throws Exception{//交给被调用处处理
		int result=0;//保存计算结果
		System.out.println("************begin*************");
		try{
			result = x/y;
		}finally{
			System.out.println("*************end*************");
		}
		return result;
	}
}
public class Hello{
	public static void main(String args[]) {//throws Exception
		try{
			System.out.println(MyMath.div(10, 0));
		}catch(Exception e)	{
			e.printStackTrace();
		}
	}
}

异常的捕获及处理

RuntimeException类

看段代码:

public class Hello{
	public static void main(String args[]) {
		int num = Integer.parseInt("123");
		System.out.println(num*num);
	}
}

异常的捕获及处理
异常的捕获及处理
方法中出现throws就要进行异常处理,但此时并没有,观察NumberFormat类的继承结构。
异常的捕获及处理
因为NumberFormat类属于RuntimeException的子类,所以该异常属于选择性处理,即使不处理,编译的时候也不会出错,但是运行的时候会出错。
面试题:请解释Exception与RuntimeException的区别?列举出几个常见的RuntimeException。

  • RuntimeException是Exception的子类;
  • Exception定义的异常都需要强制性的处理,而RuntimeException的子类在编写代码时异常不需要强制性处理,由用户自己选择,如果不处理并且产生异常将交由JVM负责处理。
  • 常见的RuntimeException:ArithmeticException,NullPointerException、ClassCastException、NumberFormatException。

断言:assert(了解)

断言指的是在程序编写的过程之中,确定代码执行到某行之后数据一定是某个期待的内容。
范例:观察断言
异常的捕获及处理
断言默认情况不会启用,只有在程序运行时增加了配置参数才可以使用。
异常的捕获及处理
java -ea Hello
异常的捕获及处理

自定义异常类

Java异常类之中提供了大量类型,但是这些类型之中几乎都是与语法有关的异常,缺少业务有关类型,例如:输入某人成绩,如果超过100,那么就应该产生对应的异常,这些往往需要开发者自己定义,正因为如此才需要自定义异常类的概念。
异常类型主要有两个:Exception、RuntimeException。
范例:设计一个成绩异常
异常的捕获及处理
异常的捕获及处理

总结

异常的捕获及处理