Exception类

异常类

/*

  • 什么是异常(Exception)
  • 异常是程序在编译或运行过程中出现的例外,这些例外有的可以避免,有的却无法避免。
  • Exception类继承自Throwable类,Throwable类还有一个子类Error
  • Error代表的是错误,不再是程序员编程处理的范围。
  • 检查异常也称为编译期异常
  • 不可避免,必须进行异常处理,要不编译器报错
  • Exception以及它的子类(除去RuntimeException)
  • 未检查异常也称为运行时异常
  • 可以避免,不需要必须处理
  • RuntimeException以及它的子类

*/

常见的异常

package SE02.n1Exception;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo01Exception {
	public static void main(String[] args){
//		常见的运行时异常
//		NullPointerException 空指针异常
		String name=null;
		System.out.println(name.toString());
		
//		ArithmeticException 算数异常
		System.out.println(1/0);
		
//		ArrayIndexOutOfBoundsException 数组下标越界异常
		String s[]=new String[2];
		System.out.println(s[3]);
		
//		ClassCastException 类型转换异常
		Object o=new Integer(20);
		String s= (String)o;
		
//		常见编译期异常
//		ParseException 解析异常
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="1000年2月2日";
		Date d=sdf.parse(string);//需异常处理

		
	}
}

异常处理方法

// Java编译期异常必须处理,否则编译器会提示错误,且源文件无法成功编译
// 处理方法两种
// 1.使用try_catch_finally关键字捕获并处理
// 2.使用throws关键字声明抛出异常,让别人去处理

try_catch_finally关键字

package SE02.n1Exception;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo02try_catch {
	public static void main(String[] args) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="1000年2月2日";
		try {
			Date d=sdf.parse(string);//需异常处理
		} catch (ParseException e) {
			// TODO 自动生成的 catch 块
			System.out.println("try语句中发生异常,会跳转到此语句块执行");
			e.printStackTrace();//打印栈路径
		}finally {
//			不论是否捕捉到异常都要执行的代码块
			System.out.println("执行了finally代码块!!!");
		}
	}
}

在try_catch语句块中有一个特殊情况:return的用法以及细节

在try_catch_finally这三个语句块中分别执行return会有不同的细节,上代码!

package SE02.n1Exception;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo03Retrun {
	public static void main(String[] args) {
		System.out.println(test1());
//		System.out.println(test2());
//		System.out.println(test3());
//		System.out.println(test4());
	}

	private static String test1() {
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="1000年2月2日";//代码正常,可以被正常年月日格式化
		String rStr="begin";
		try {
			Date d=sdf.parse(string);//需异常处理
			return rStr;//上一条报错,此条不可达,不运行
		}catch(ParseException e){
			rStr="catch";
			return rStr;//先封存,再finally,再return封存
			
		}finally {
			rStr="finally";
			return rStr;
		}

当return写在finally代码块中时,无论是无异常还是有异常,最后返回的都是“finally”
接下来进行分类讨论:
(1)当try语句中的代码无异常:
try中的return rStr不会立马执行,会将rStr的内存地址封存在一个空间中,等finally代码块执行完才会return封存的内存地址,再根据内存地址寻找要输出的字符串。但是,当finally代码块中有return关键字时,程序会优先执行finally代码块中的return关键字,try语句块中的return封存的内存地址将被永久封存,return的是finally代码块中的rStr。
(2)当try语句中的代码需要异常处理:
同样的是封存try中的return,进入catch,再对catch中的return进行封存,最后执行finally中的代码块,若finally中有return语句,则执行finally中的return语句,而try和catch中return封存的值将永久封存,最终输出finally中的return。
所以上面代码输出的结果为:finally

以上是finally中有return的情况

下面介绍finally中没有return的情况

话不多说先上代码!

	private static String test1() {

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="2000年2月2日";//该字符串在格式化年月日时不会抛出异常,格式正确
		String rStr="begin";
		try {
			Date d=sdf.parse(string);//不需要异常处理
			return rStr;//此条可达,执行
		}catch(ParseException e){
			rStr="catch";
			return rStr;//先封存,再finally,再return封存	
		}finally {
			System.out.println("这里是finally代码块");
		}
	}

先上输出结果: 这里是finally代码块
begin
语句依次执行try—>catch—>finally。在执行try时:Date d=sdf.parse(string)执行完毕后,执行return语句,封存rStr的内存地址(begin),跳过catch语句块,执行finally语句块中的输出语句,最后return封存中的begin

	private static String test1() {

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="2000年2月2日";//该字符串在格式化年月日时会抛出异常,非正确格式
		String rStr="begin";
		try {
			Date d=sdf.parse(string);//需要异常处理
			return rStr;//此条不可达,不执行
		}catch(ParseException e){
			rStr="catch";
			return rStr;//先封存,再finally,再return封存	
		}finally {
			System.out.println("这里是finally代码块");
		}
	}

先上输出结果: 这里是finally代码块
finally
同样,语句依次执行try—>catch—>finally。在执行try时:Date d=sdf.parse(string)会抛出异常,从而导致直接跳进catch语句块,使return不可达。进入catch语句后:此时rStr重新赋值。(注意!java中String类型的对象是固定的不变的,在本人的其他博客中有详细介绍String类型)此时的rStr和最开始定义的String rStr="begin"的内存地址是不同的,虽然变量名相同,但内存地址不同,这里的return封存的就是内存地址,所以现在封存的是catch。最后执行finally代码块的输出语句,再return rStr。

以上是return String类型的语句看不出太明显的细节

下面介绍return int类型的try_catch

private static int test2() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="100年2月2日";
		int i =0;
		try {
			Date d=sdf.parse(string);//可能需异常处理的语句
			i=1;
			return i;
		}catch(ParseException e){
			System.out.println("catch");
			i=2;
			System.out.println("ii");
			return i;//先封存(基本数据类型的值)(八种数据类型的值可以直接放在栈中),再finally,再return封存
		}finally {
			i=3;
			System.out.println("finally");
			return i;
		}
	}

先上结果: finally
3
同样如果finally中有return,不管try和catch中的封存,直接执行return中的封存。

private static int test2() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="100年2月2日";
		int i =0;
		try {
			Date d=sdf.parse(string);//需异常处理
			i=1;
			return i;
		}catch(ParseException e){
			System.out.println("catch");
			i=2;
			System.out.println("ii");
			return i;//先封存(基本数据类型的值)(八种数据类型的值可以直接放在栈中),再finally,再return封存
		}finally {
			i=3;
			System.out.println("finally");
		}
	}

先上结果: finally
1
需要注意的是:finally代码块中虽然i被重新赋值,但是try中的return已经率先封存了i=1的内存地址,所以…
与String类型相似的是:先封存(基本数据类型的值)(八种数据类型的值可以直接放在栈中),再finally,再return封存

以上是int型与String类型类似,下面介绍一种比较特殊的类型

自己新建一个Class:Person类 令try_catch语句的返回值为Person

Person类

package SE02.n1Exception;

public class Person {
	int age=0;
	@Override
	public String toString() {
		return "Person [age=" + age + "]";
	}
}

	private static Person test3() {

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="20**年2月2日";
		Person p =new Person();//此时p.age=0
		try {
			Date d=sdf.parse(string);//需异常处理的代码
			System.out.println("try");//若进行异常处理,则代码不可达
		}catch(ParseException e){
			p.age=12;
			System.out.println("catch");
			return p;//先封存(引用的地址值),再finally,再return封存
		}finally {
//			p.age=11;
			System.out.println("finally");
		}
		return p;
	}

先上结果: catch
finally
Person [age=12]
由于封存的都是p的内存地址,所以每次p的属性被重新赋值都会改变封存中的内容。所以如果finally中有有关p对象的赋值语句,return中的封存内容就会被改写(内存地址值不变)。

private static Person test3() {

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="20**年2月2日";
		Person p =new Person();
		try {
			Date d=sdf.parse(string);//需异常处理
			System.out.println("try");
		}catch(ParseException e){
			p.age=12;
			System.out.println("catch");
			return p;//先封存(引用的地址值),再finally,再return封存
		}finally {
			p.age=11;
			System.out.println("finally");
		}
		return p;
	}

先上输出结果: catch
finally
Person [age=11]

当finally中有赋值语句,就会改写封存内容

以上是返回Person类,下面看StringBuilder类的相关细节

	private static StringBuilder test4() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="100#0年2月2日";
		StringBuilder rStr=new StringBuilder("begin");
		try {
			Date d=sdf.parse(string);//需异常处理
			return rStr;//上一条报错,此条不可达,不运行
		}catch(ParseException e){
			rStr.append("catch");
			return rStr;//先封存,再finally,再return封存
			
		}finally {
			rStr.append("finally");
			return new StringBuilder("finally");
		}
	}
}

先上结果: finally
原因:finally中出现return,其他语句块的封存全部失效

	private static StringBuilder test4() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
		String string="100#0年2月2日";
		StringBuilder rStr=new StringBuilder("begin");
		try {
			Date d=sdf.parse(string);//需异常处理
			return rStr;//上一条报错,此条不可达,不运行
		}catch(ParseException e){
			rStr.append("catch");
			return rStr;//先封存,再finally,再return封存
			
		}finally {
			rStr.append("finally");
		}
	}
}

注:有关StringBuilder的相关介绍和方法介绍在本人其他博客中有详解,请客官移步。
先上输出结果:begincatchfinally
从输出结果中可以看出,rStr游历了所有语句块,同样的是return封存了内存地址,而rStr对象中的属性改变,return出的rStr依旧会是append后的结果

由于篇幅较长,下一篇写自定义异常

©️2020 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值