Java中的异常详解

Java 中的异常详解

异常的定义

定义: 异常(Exception)是一个发生在程序运行中的事件。它会破坏程序指令流的正常运行。
异常类

异常的分类

异常经常被分为3个不同的种类:

  • The checked exception (受检异常)
  • The runtime exception
  • The error

受检异常在正常的程序编写中,软件会提醒程序员对相关代码命令作异常处理,如:调用 java.io.FileReader 中的相关方法。
但有些异常并不会在编写代码时得到提示,如:NullPointerException。这种报错一般情况下都会在我们执行代码的时候报错的控制台。这种就属于 the runtime exception。
而error多是由于外部因素引起而非代码本身,如:IO口调用失败。
∗ * error 和 runtime exception 都无法被提前预知并做相应的处理,所以被成为“非受检异常”

异常处理

通常,在Java中处理抛出异常的方法有两种:

  • try … catch
  • 方法中提供 throws 条款
    (官方文档用词是 throws clause,不知这里翻译为throws 条款是否正确)

try … catch

基本写法
// 基本结构
try{
	// 基本逻辑代码
} catch(异常 e) {
	// 对于异常的处理方法
} finally {
	// 一定会执行的代码
}

这个结构可以根据具体需要进行省略一些内容:

// 省略 finally 部分
try {
} catch() {
}

// 省略 catch 部分
try {
} finally {
}

当遇到要同时捕捉多个异常的时候,就可以增加 catch 部分的数量来实现。
对每一个捕捉到的异常做相应的处理。但如果所有需要捕捉的异常都可以用相同的方式进行处理,我们可以把需要捕捉的异常全部放在一个catch中,具体写法如下:

// 每种异常都做不同处理
try{
	// 基本逻辑代码
} catch(异常1 e) {
	// 对于异常1的处理方法
} catch(异常2 e) {
	// 对于异常1的处理方法
}
// 所有异常一起处理
try {
} catch(异常1 | 异常2 | 异常3 e) {
	// 异常1、2、3共同的处理方法
}
运行顺序

以下面一段代码为例

public class Test {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);

		int age = 0;
		try {
			System.out.println("Please enter an age:");
			age = in.nextInt();
			System.out.println("age assigned successfully");
		} catch (Exception e) {
			System.out.println("The input age is invalid.");
		} finally {
			System.out.println("final");
		}

		in.close();
	}
}

代码结果输出如下:
在这里插入图片描述
不难看出,这里使用的是基本的 try … catch 结构,就是用try后的代码块执行基本的逻辑代码。如果输入12,12为数字则不会产生异常。在执行完 try中的语句后t跳过catch执行finally中的代码。
在这里插入图片描述

如果在该部分代码运行中有异常出现,则用catch捕捉,程序从异常出现的语句停止,跳转到catch部分,之后由catch后的代码块执行对捕捉到的异常进行的处理。最后执行finally中的代码。

当 try 后的代码块中有return时

public class Test {
	public static int func() {
		int age = 0;
		try {
			age = 6;
			System.out.println("try: " + age);

			return age;
		} catch (Exception e) {
		} finally {
			age = 8;
			System.out.println("final: " + age);
		}

		return -1;
	}

	public static void main(String[] args) {
		System.out.println("main: " + func());	
	}
}

输出:
在这里插入图片描述
根据输出可以得到代码的执行顺序为: try -> finally -> main。由此可知,代码在 return 前先要执行 finally 后的代码块。

但这里finally中对age赋值为 8,并没有返回到main中。原因是:在 func 方法执行到 try 中的 return 时,会对此时栈中 age 的值进行备份用以在后面执行 return 操作,而此时 age 的值为6。在这之后程序运行 finally 中的赋值语句,把 age 从 6 赋为 8。

throws 条款

throws 关键字多于抛出传参时因参数导致的异常。

	public static int func(String x) throws NumberFormatException {

		return  Integer.parseInt(x);
	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String x = sc.nextLine();

		try {
			System.out.println("main: " + func(x));
		} catch (NumberFormatException e) {
			System.out.println("\"x\" cannot convert to integer");
		}	

		sc.close();
	}

当把 x 赋值为 a 时,输出:
在这里插入图片描述

在正常情况下,这个在输入的 x 无法转为 integer 的情况下,就会出现 NumberFormateException 的异常。此时我们可以用方法中抛出异常,再在上层的代码中进行异常处理。否则,程序会在 Integer.parseInt(x); 执行时报错。

关键字 throw

我们在代码中除了会看到 throws 关键字,还会看到 throw 关键字。
throw关键字,通常情况下用于在代码中创建自己的独有异常。

1. 根据已有的异常类抛出相应的异常
	public static void ageCheck(int age) throws RuntimeException {
		if(age < 16)
			throw new RuntimeException("he is too young!");

		System.out.println("he is an adult.");
	}
	
	public static void main(String[] args) {
		ageCheck(18);
		ageCheck(5);
	}

输出:
在这里插入图片描述

改异常为Runtime Exception,是非受检异常,所以可以直接抛出。

如果为 创建的是 Exception 就必须要在调用方法时用 try_catch 处理,因为该异常为受检异常。

	public static void ageCheck(int age) throws Exception {
		if(age < 16)
			throw new Exception("he is too young!");

		System.out.println("he is an adult.");
	}
	
	public static void main(String[] args) {
		

		try {
			ageCheck2(18);
			ageCheck2(5);
		} catch (Exception e) {
			System.out.println("I am 5, i am too young.");
		}
	}

输出:
在这里插入图片描述

2. 创建新异常

创建一个异常,需要创建一个新的 class,再根据需要看是继承 Exception,还是 RuntimeException,这两个的区别就在于继承 Exception 的异常会被认为是 受检异常,而继承 RuntimeException 的异常是非受检异常。

class RangeException extends Exception {

	public RangeException(String message) {
		super(message);
	}
}

public class Test {

	public static void ageCheck2(int age) throws RangeException {
		if(age < 16) {
			RangeException e = new RangeException("he is too young!");
			throw e;
		}
			
		System.out.println("he is an adult.");
	}
	
	public static void main(String[] args) {

		try {
			ageCheck2(18);
			ageCheck2(5);
		} catch (Exception e) {
			System.out.println("I am 5, i am too young.");
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值