Exception异常处理

本文详细介绍了Java中的异常处理机制,包括错误的分类(Error和Exception)、异常的抛出与捕获(如try-catch-finally结构),以及如何通过继承体系自定义异常。重点强调了CheckedException和RuntimeException的区别以及如何在编程中适当地处理这些异常情况。
摘要由CSDN通过智能技术生成

Java的异常

在计算机程序运行的过程中,总是会出现各种各样的错误。有一些是用户造成的,还有一些错误是随机出现,并且无法避免的,比如:

  • 网络突然断了,连接不到服务器
  • 内存耗尽,程序崩溃
  • 用户点“打印”,但没有连接打印机

因此,一个健壮的程序必须处理各种错误,错误就是在程序运行期间,调用某个函数的时候,如果失败了,就代表出错

调用方获知调用失败的信息的方式有两种:

1、约定返回错误码。例如处理一个文件,返回0代表成功,返回其他数表示约定的错误码。

2、在语言层面上提供一个异常处理机制。Java内置了一套异常处理机制,总是使用异常来表示错误。异常是一种class,因此它本身带有类型信息。异常可以在任何地方抛出,但只需要在上次捕获,这样就和方法调用分离了。

因为Java的异常体系是基于class面向对象思想设计的,所以它的继承关系如下图:

                           

从继承关系可知:Throwable是异常体系的根,它继承自Object。Throwable有两个体系:Error和Exception。

Error表示严重的错误,程序对此一般无能为力,例如:

  • OutOfMemoryError:内存耗尽
  • NoClassDefFoundError:无法加载某个class
  • StackOverflowError:虚拟机栈溢出

Exception则是运行时的错误,它可以被捕获并处理。某些异常是应用程序逻辑处理的一部分,应该捕获并处理。例如:

  • NumberFormatExpection:数据类型的格式错误
  • FileNotFoundException:未找到文件
  • SocketException:读取网络失败

还有一些异常是程序逻辑编写不对造成的,应该修复程序本身。例如:

  • NullPointerException:对某个null的对象调用方法或字段
  • IndexOutodBoundsException:数组索引越界

Exception又分为两大类:

  • RuntimeException:以及它的子类;
  • RuntimeException(包括IOExceptionReflectiveOperationException等等)

Java规定:

  • 必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception
  • 不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。

捕获异常

在Java中,凡是可能抛出异常的语句,都可以用try……catch捕获。把可能发生的异常的语句放在try{......}中,然后使用catch捕获对应的Exception及其子类。

多catch语句

try: 包围可能产生异常的代码块如果产生异常,系统会根据异常产生的原因,创建一个异常对象。
catch: 捕获异常,处理异常。

try(Scanner in=new Scanner(System.in)){
	//获取输入时,可能产生InputMismatchException
			
	//输入非法内容:a
	//JVM创建一个InputMismactchException类型的异常对象,并抛出
	//程序会从try块退出
	int n1=in.nextInt();//输入a
			
	int n2=in.nextInt();
			
	//计算除法时,可能产生ArithmeticException
	System.out.printf("%d÷%d=%d",n1,n2,n1/n2);
}catch(NullPointerException ex) {
	System.err.println("空指针");
}catch(InputMismatchException ex) {
	System.err.println("输入有误");
}catch(ArithmeticException ex) {
	System.err.println("算数逻辑有误");
}

输入:

a

输出结果为:
输入有误

需要注意的是,存在多个catch时,catch包裹的子类必须写在前面。

finally语句

如果有无论是否有异常的发生,我们都需要执行的语句,那么Java的try……catch机制还提供了finally语句,finally语句块保证有无错误都会执行。

public static void main(String[] args) {
	System.out.println("输出结果res="+todo());
}
	
public static int todo() {
	int n=8;
	int res=0;
	try {
		n=n/0;//出现异常
		res=n*10;//res=80;
			
		//return前,缓存返回值,再去执行finally
		return res;
	}catch(Exception ex) {
		System.out.println("出现异常!");
		res=n+10;
		return res;
	}finally {
		res=res+100000;
		System.out.println("执行fianlly");
    }
}

输出结果为:

出现异常!
执行fianlly
输出结果res=18

finally有几个特点:

  • finally语句不是必须的,可以不写。
  • finally总是最后执行。

抛出异常

当发生错误时,例如,用户输入了非法的字符,我们就可以抛出异常。

抛出异常分两步:

1、创建某个Exception的实例

2、用throw语句输出;

public static void main(String[] args) {
		String str="唧唧复唧唧木兰当户织不闻机杼声";
		String res=copy(str,20,9);//注意这里的第二个参数有误
		System.out.println(res);
	}
	
	//复制字符串
	public static String copy(String s,int startIndex,int endIndex) {
		
		//输入判断
		//方式1:不常用
		if(s==null) {
			NullPointerException NPE=new NullPointerException();//无参构造方法
			throw NPE;
		}
		
		//方式2:直接抛出新对象不必命名
		if(startIndex>endIndex) {
			throw new IllegalArgumentException("开始下标不能大于结束下标");//有参构造方法,返回值为String
		}
		
		if(startIndex<0||endIndex>=s.length()) {
			throw new StringIndexOutOfBoundsException("下标超出字符串的范围");
		}
		
		//复制字符串
		char[] arr=s.toCharArray();
		
		StringBuilder sb=new StringBuilder();
		for (int i = startIndex; i <= endIndex; i++) {
			char c=arr[i];
			sb.append(c);
		}
		return sb.toString();
	}

输出结果为:

Exception in thread "main" java.lang.IllegalArgumentException: 开始下标不能大于结束下标
    at Throw.throw01.copy(throw01.java:22)
    at Throw.throw01.main(throw01.java:6)


自定义异常

我们也可以根据自己的需求来自定义新的异常类型,但是保持一个合理的异常继承体系是非常重要的。一个常见的做法就是自定义一个BaseException作为"根异常",然后派生出各种业务类型的异常。BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生。
 

public static void main(String[] args) throws NotEnoughException {
	work();
}
	
public static void work() throws NotEnoughException {
	System.out.println("初始库存"+Reposistory.stock);
		
	//入库
	Reposistory.in(20);
	System.out.println("库存"+Reposistory.stock);
		
	//出库
	//调用方法,如果声明抛出检查异常时
	//该方法必须使用try...catch处理
	//或者使用throws声明抛出
	Reposistory.out(1000);
	
	System.out.println("库存"+Reposistory.stock);
	}
}

//仓库类
class Reposistory{
	static int stock=100;//库存数量
	
	//入库
	public static void in(int count) {
		stock=stock+count;
	}
	
	//出库
	public static void out(int count) throws NotEnoughException {
		if(count>stock) {
			//如果抛出RuntimeException运行时异常,
			//可以省略异常类型的方法声明 throws RuntimeException
			//throw new RuntimeException("库存不足");
			
			//如果抛出检查异常(编译器异常)
			//必须完成异常类型的方法声明 throws NotEnoughException
			throw new NotEnoughException();
		}
		stock=stock-count;
	}
}

//自定义异常
//库存不足异常
class NotEnoughException extends Exception{
	public NotEnoughException() {
		super("库存不足!");
    }
}

输出结果为:

初始库存100
库存120
Exception in thread "main" NewExpection.NotEnoughException: 库存不足!
    at NewExpection.Reposistory.out(NewException01.java:49)
    at NewExpection.NewException01.work(NewException01.java:19)
    at NewExpection.NewException01.main(NewException01.java:5)

上面的结果中NotEnoughException为自定义的异常类型。


Exception异常处理思维导图

以上是我个人对Exception异常处理的一些总结,如有错漏请务必联系,非常感谢

`InvocationTargetException` 是 Java 反射机制中常见的异常,当调用某个方法或构造函数时,如果该方法或构造函数抛出了异常,那么反射机制会将原始的异常包装成 `InvocationTargetException` 异常并抛出。因此,我们在使用反射机制调用方法或构造函数时,需要特别注意该异常的处理。 在处理 `InvocationTargetException` 异常时,我们需要先通过 `getCause()` 方法获取原始异常,并根据原始异常的类型进行相应的处理。下面是一个示例代码: ```java try { Method method = MyClass.class.getMethod("myMethod"); method.invoke(new MyClass()); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { if (e instanceof InvocationTargetException) { Throwable cause = e.getCause(); if (cause instanceof MyException) { // 处理 MyException 异常 } else { // 处理其他异常 } } else { // 处理其他异常 } } ``` 在上述代码中,我们首先通过 `getMethod()` 方法获取指定类的指定方法,在使用 `invoke()` 方法调用该方法时,如果该方法抛出了异常,那么就会抛出 `InvocationTargetException` 异常。在捕获该异常后,我们先通过 `getCause()` 方法获取原始异常,并根据原始异常的类型进行相应的处理。 需要注意的是,`InvocationTargetException` 异常一般是由于被调用方法或构造函数内部抛出了异常导致的,因此我们在处理该异常时,通常要先检查原始异常的类型,并根据具体情况进行处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓晨CH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值