26-异常的捕获和处理

异常的捕获和处理

Java强大在异常的处理操作上

认识异常对程序的影响

异常指的是导致程序中断的指令流。
出现错误之后整个程序不会按照既定的方式执行而是中断了执行。为了保证程序出现非致命错误之后仍可以正常完成,以保证程序的顺利进行。

处理异常

Java中进行异常处理,可以使用try、catch、finally这几个关键字来完成,基本的处理结构如下:

try{
    
    
	// 可能出现异常的语句
}[catch (异常类型 异常对象){
    
    
	// 异常处理
}
catch (异常类型 异常对象){
    
    
	// 异常处理
}...][finally{
    
    
	// 不管异常是否处理都要执行
}]

可以使用的组合:try…catch,try…catch…finally,try…finally.
此时在异常处理的时候直接输出的是一个异常类的对象,那么对于此对象如果直接打印所得到的异常信息不完整,若想获得完成的异常信息,可以使用异常类中提供的printStackTrace()方法完成。
对于异常的处理格式也可以在最后追加有一个finally程序块,表示异常处理的出口,不管程序是否异常都进行处理。

处理多个异常

产生若干个异常的处理,这种情况下也可以使用多个catch进行异常的捕获。
异常类型:

  • 忘记输入参数:数组越界异常
  • 输入类型错误:数字格式异常
  • 数据异常:被除数不得为0

异常处理流程

进行异常处理的时候将所有可能已经明确知道要产生的异常都进行了捕获,虽然可以得到良好的代码结构,但是这种代码编写非常麻烦,所以在想要进行合理异常就必须清除在异常产生之后程序到底做了哪些处理。
DzeAJg.png

  1. 程序运行的过程中才会产生异常,而一旦程序执行中产生了异常将自动进行指定类型的异常类对象实例化处理;
  2. 如果此时程序并没有提供有异常处理的支持,则会采用JVM默认异常处理,首先打印异常信息而后退出执行;
  3. 如果此时程序有提供有异常处理,那么这个产生的异常类的实例化对象会被try语句捕获;
  4. try捕获到异常后,与其匹配的catch异常类型进行一次比对;匹配则使用此catch进行异常处理,若没有任何成功匹配,那么表示该异常无法处理;
  5. 最后执行finally语句,完成finally后会进一步判断当前异常是否已经处理过,若处理则继续向后执行,若未处理则交由JVM进行默认处理。

在整个异常处理中实际上操作的还是一个异常类的实例化对象,那么这个异常类的实例化对象类型成为了理解异常处理的核心关键所在。
在程序中可以处理的异常的最大的类型就是Throwable,有两个子类:

  • Error:此时程序还未执行出现的错误,开发中无法处理。
  • Exception:程序中出现的异常,开发者可以处理。

通过分析可以发现异常产生的时候会产生异常的实例化对象,那么按照对象引用原则,可以自动向父类转型,按此逻辑,所有的异常都可以使用Exception来处理。

catch(Exception e){
    
    
	e.printStackTrace();
}

当不确定产生哪些异常时,这样处理简单,这样处理的问题是描述的错误信息不明确,所以分开处理异常是一种可以更加方便明确的处理方式。
在以后进行多个异常同时处理的时候要把捕获范围大的异常放在捕获范围小的异常之后。

throws关键字

通过之前程序在程序执行中可能产生异常,假设定义了一个方法,就应明确告诉使用者会产生何种异常。此时就可以在方法的声明上使用throws关键字来进行异常类型的额标注。

class Math{
    
    
	//这个代码执行时可能会产生算术异常,如果产生异常"调用处"处理
	public static int div(int x, int y) throws ArithmeticException{
    
    
		return x/y;
	}
}
main throws Exception{
    
    		//主方法向上抛出异常
	Math.div(10,2);
}

主方法本身也是一个方法,产生的异常也可以向上抛出;表示异常由JVM负责处理。

throw关键字

throw表示手工进行异常的抛出,此时手工产生异常的实例化对象并且进行异常的抛出处理。

main{
    
    
	try{
    
    		//异常对象是手工定义的
		throw new Exception("自己跑着玩的对象。");
	} catch(Exception e){
    
    
		e.printStackTrace();
	}
	
}

面试:解释throws和throw的区别?

  • throw:代码块中使用,主要是手工进行异常对象的抛出;
  • throws:是在方法定义上使用的,表示将此方法可能产生的异常明确告诉调用处,由调用处处理。

异常处理模型

class Math{
    
    
	//这个代码执行时可能会产生异常,如果产生异常"调用处"处理
	public static int div(int x, int y) throws Exception{
    
    
		int temp = 0;
		print("start");
		try{
    
    
			temp = x/y;
		} catch(Exception e){
    
    
			throw e; 		//向上抛异常对象
		} finally{
    
    
			print("end");
		}
		return temp;
	}
}
main{
    
    		
	try{
    
    
		Math.div(10,2);
	} catch (Exception e){
    
    
		e.printStackTrace();
	}
}

对此类可省略掉Math中的catch,实际开发中此种异常处理格式十分重要(资源访问时)。

RuntimeException

只要方法带有throws会告诉用户产生何种异常。
若现在程序执行上只要使用了throws定义的方法都必须要求开发者手工处理,则该代码过于麻烦,所以在设计过程中,提供一个灵活的可选的异常处理父类"RuntimeException",这个类的异常的子类可以不需要强制性处理。
面试:解释RuntimeException和Exception的区别?列举常见的RuntimeException。

  • RuntimeException是Exception的子类;
  • RuntimeException标注的异常可以不需要进行强制性处理,而Exception异常必须强制性处理。
  • 常见:NumberFormatException、ClassCastException、NullPointerException

自定义异常类

JDK中提供大量异常类型,实际开发中可能未必足够,此时考虑自定义异常类。
两种实现方案:继承Exception或RuntimeException;

class BombException extends Exception{
    
    
	public BombException(String msg){
    
    
		super(msg);
	}
}
class Food{
    
    
	public static void eat(int num) throws BombException{
    
    
		if(num > 10 ){
    
    
			throw new BombException("TOO MUCH");
		} else{
    
    
			print("normal");
		}
	}
}

assert断言

JDK1.4之后追加一个断言的功能,确定代码执行到某行之后一定是所期待的结果,实际开发中断言不一定是正确的,也有可能出现偏差,但这种偏差不应影响程序正常执行。
Java中并未将断言设置为一个程序必须执行的步骤,需要特定环境下才可以开启。

猜你喜欢

转载自blog.csdn.net/MARVEL_3000/article/details/111467178
今日推荐