Java异常处理

Java异常处理

在这里插入图片描述

Java 通过面向对象的方法进行异常处理,一旦方法抛出异常,系统自动根据该异常对象寻找合适的异常处理器(Exception Handler)来处理该异常,把各种不同的异常进行分类,并提供了良好的接口。在 Java 中,每个异常都是一个对象,它是Throwable 类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。Java 的异常处理是通过 5 个关键词来实现的:try、catch、throw、throws 和finally

在Java应用中,异常的处理机制分为声明异常,抛出异常和捕获异常

声明异常

通常,应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去。传递异常可以在方法签名处使用throws关键字声明可能会抛出的异常

注意:

  • 非检查异常(Error,RuntimeException或它们的子类)不可使用throws关键字来声明要抛出的异常
  • 一个方法出现编译时异常,就需要try-catch/throws处理,否则会导致编译错误

抛出异常

如果你觉得解决不了某些异常问题,且不需要调用者处理,那么你可以抛出异常

throw关键字作用是在方法内部抛出一个Throwable类型的异常.任何Java代码都可以通过throw语句抛出异常

捕获异常

长须通常在运行之前不报错,但是运行后可能会出现某些未知的错误,但是还不想直接抛出到上一级,那么就需要通过try-catch的形式进行异常捕获,之后根据不同的异常情况进行相应的处理

如何选择异常类型

根据下图来选择是捕获异常,声明异常还是抛出异常

在这里插入图片描述

常见异常处理方式

直接抛出异常

通常,应该捕获那些知道如何处理的异常,将不知道如何处理的异常继续传递下去。传递异常可以在方法签名处使用 throws 关键字声明可能会抛出的异常

private static void readFile(String filePath) throws IOException
{
	File file = new File(filePath);
	String result;
	BufferedReader reader = new BufferedReader(new
FileReader(file));
	while((result = reader.readLine())!=null) {
		System.out.println(result);
	} 
	reader.close();
}

封装异常再抛出

有时我们会从 catch 中抛出一个异常,目的是为了改变异常的类型。多用于在多系统集成时,当某个子系统故障,异常类型可能有多种,可以用统一的异常类型向外暴露,不需暴露太多内部异常细节

private static void readFile(String filePath) throws MyException
{
	try {
		// code
	} catch (IOException e) {
		MyException ex = new MyException("read file failed.");
		ex.initCause(e);
		throw ex;
	}
}

捕获异常

在一个 try-catch 语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理

private static void readFile(String filePath) {
	try {
		// code
	} catch (FileNotFoundException e) {
		// handle FileNotFoundException
	} catch (IOException e){
		// handle IOException
	}
}

同一个catch也可以捕获多种类型异常,用 | 隔开

private static void readFile(String filePath) {
	try {
		// code
	} catch (FileNotFoundException | UnknownHostException e) {
		// handle FileNotFoundException or UnknownHostException
	} catch (IOException e){
		// handle IOException
	}
}

自定义异常

习惯上,定义一个异常类应包含两个构造函数,一个无参构造函数和一个带有详细描述信息的构造函数(Throwable 的 toString 方法会打印这些详细信息,调试时很有用)

public class MyException extends Exception {
	public MyException(){ }
	public MyException(String msg){
		super(msg);
	} 
	// ...
}

try-catch-finally

当方法中发生异常,异常处之后的代码不会再执行,如果之前获取了一些本地资源需要释放,则需要在方法正常结束时和 catch 语句中都调用释放本地资源的代码,显得代码比较繁琐,finally 语句可以解决这个问题

private static void readFile(String filePath) throws MyException
{
	File file = new File(filePath);
	String result;
	BufferedReader reader = null;
	try {
		reader = new BufferedReader(new FileReader(file));
		while((result = reader.readLine())!=null) {
			System.out.println(result);
		}
	} catch (IOException e) {
		System.out.println("readFile method catch block.");
		MyException ex = new MyException("read file failed.");
		ex.initCause(e);
		throw ex;
	} finally {
		System.out.println("readFile method finally block.");
		if (null != reader) {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

调用该方法时,读取文件时若发生异常,代码会进入 catch 代码块,之后进入finally 代码块;若读取文件时未发生异常,则会跳过 catch 代码块直接进入 finally代码块。所以无论代码中是否发生异常,fianlly 中的代码都会执行

若 catch 代码块中包含 return 语句,finally 中的代码还会执行吗?将以上代码中的catch 子句修改如下:

catch (IOException e) {
	System.out.println("readFile method catch block.");
	return;
}

调用 readFile 方法,观察当 catch 子句中调用 return 语句时,finally 子句是否执行

readFile method catch block.
readFile method finally block

可见,即使 catch 中包含了 return 语句,finally 子句依然会执行。若 finally 中也包含 return 语句,finally 中的 return 会覆盖前面的 return

try-with-resource

上面例子中,finally 中的 close 方法也可能抛出 IOException, 从而覆盖了原始异常。JAVA 7 提供了更优雅的方式来实现资源的自动释放,自动释放的资源需要是实现了 AutoCloseable 接口的类

private static void tryWithResourceTest(){
	try (Scanner scanner = new Scanner(new
FileInputStream("c:/abc"),"UTF-8")){
		// code
	} catch (IOException e){
		// handle exception
	}
}

try 代码块退出时,会自动调用 scanner.close 方法,和把 scanner.close 方法放在finally 代码块中不同的是,若 scanner.close 抛出异常,则会被抑制,抛出的仍然为原始异常。被抑制的异常会由 addSusppressed 方法添加到原来的异常,如果想要获取被抑制的异常列表,可以调用 getSuppressed 方法来获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值