java知识4-----异常

异常的基本概念

异常是导致程序中断运行的一种指令流。如果不对异常进行正确的处理,则可能导致程序的中断执行,造成不必要的损失,所以在程序的设计中必须要考虑各种异常的发生,并正确的做好相应的处理,这样才能保证程序的正常执行。

public class ExceptionDemo01{
	public static void main(String args[]){
		System.out.println("********** 计算开始 ***********") ;
		int i = 10 ;		// 定义整型变量
		int j = 0 ;			// 定义整型变量
		int temp = i / j ;	// 此处产生了异常
		System.out.println("两个数字相除的结果:" + temp) ;
		System.out.println("********** 计算结束 ***********") ;
	}
};

在这里插入图片描述
产生异常之后的语句没有执行。

一旦产生异常,异常之后的语句并不会执行,而是直接结束程序,并将错误报告出来给用户。

异常的基本处理格式

在这里插入图片描述
try中捕获异常,捕获之后与catch中的异常相匹配,如果匹配成功则执行catch中的语句;不管匹配成功不成功最后都执行finally语句,从finally语句中出去。

public class ExceptionDemo02{
	public static void main(String args[]){
		System.out.println("********** 计算开始 ***********") ;
		int i = 10 ;		// 定义整型变量
		int j = 0 ;			// 定义整型变量
		try{
			int temp = i / j ;	// 此处产生了异常
			System.out.println("两个数字相除的结果:" + temp) ;// 未执行
			System.out.println("----------------------------") ; // 未执行
		}catch(ArithmeticException e){
			System.out.println("出现异常了:" + e) ;
		}
		System.out.println("********** 计算结束 ***********") ;
	}
};

产生异常之后的语句没有执行。
在这里插入图片描述

异常类的继承结构

在这里插入图片描述
一般情况下,开发者习惯于将Exception和Error统称为异常。

java异常处理机制

在这里插入图片描述
注意点:
捕获更粗的异常,要放在更细的异常之后。

public class ExceptionDemo06{
	public static void main(String args[]){
		System.out.println("********** 计算开始 ***********") ;
		int i = 0 ;		// 定义整型变量
		int j = 0 ;			// 定义整型变量
		try{
			String str1 = args[0] ;		// 接收第一个参数
			String str2 = args[1] ;		// 接收第二个参数
			i = Integer.parseInt(str1) ;	// 将第一个参数由字符串变为整型
			j = Integer.parseInt(str2) ;	// 将第二个参数由字符串变为整型
			int temp = i / j ;	// 此处产生了异常
			System.out.println("两个数字相除的结果:" + temp) ;
			System.out.println("----------------------------") ;
		}catch(ArithmeticException e){	// 捕获算术异常
			// System.out.println("算术异常:" + e) ;
			e.printStackTrace() ;
		}catch(NumberFormatException e){	// 捕获数字转换异常
			System.out.println("数字转换异常:" + e);
		}catch(ArrayIndexOutOfBoundsException e){	// 捕获数组越界异常
			System.out.println("数组越界异常:" + e) ;
		}catch(Exception e){
			System.out.println("其他异常:" + e) ;
		}
		System.out.println("********** 计算结束 ***********") ;
	}
};

如果不遵循这个更粗的异常放在更细的异常之后,会怎么样?
编译就会报错:exception has already been caught。

public class ExceptionDemo07{
	public static void main(String args[]){
		System.out.println("********** 计算开始 ***********") ;
		int i = 0 ;		// 定义整型变量
		int j = 0 ;			// 定义整型变量
		try{
			String str1 = args[0] ;		// 接收第一个参数
			String str2 = args[1] ;		// 接收第二个参数
			i = Integer.parseInt(str1) ;	// 将第一个参数由字符串变为整型
			j = Integer.parseInt(str2) ;	// 将第二个参数由字符串变为整型
			int temp = i / j ;	// 此处产生了异常
			System.out.println("两个数字相除的结果:" + temp) ;
			System.out.println("----------------------------") ;
		}catch(Exception e){
			System.out.println("其他异常:" + e) ;
		}catch(ArithmeticException e){	// 捕获算术异常,上面Exception已经捕获了异常,这里的异常永远不会执行到
			// System.out.println("算术异常:" + e) ;
			e.printStackTrace() ;
		}
		System.out.println("********** 计算结束 ***********") ;
	}
};

在这里插入图片描述

问题1:

既然所有的异常都可以使用Exception接收(都可以发生向上转型关系),那么所有的异常直接使用Exception进行接收不是更方便么?

public class ExceptionDemo08{
	public static void main(String args[]){
		System.out.println("********** 计算开始 ***********") ;
		int i = 0 ;		// 定义整型变量
		int j = 0 ;			// 定义整型变量
		try{
			String str1 = args[0] ;		// 接收第一个参数
			String str2 = args[1] ;		// 接收第二个参数
			i = Integer.parseInt(str1) ;	// 将第一个参数由字符串变为整型
			j = Integer.parseInt(str2) ;	// 将第二个参数由字符串变为整型
			int temp = i / j ;	// 此处产生了异常
			System.out.println("两个数字相除的结果:" + temp) ;
			System.out.println("----------------------------") ;
		}catch(Exception e){
			System.out.println("其他异常:" + e) ;
		}
		System.out.println("********** 计算结束 ***********") ;
	}
};

当所有的异常的处理方式都是一样的时候,就可以直接使用Exception进行捕获,当然在一个比较细致的开发中,是不建议这样使用的,所有的异常最好分别进行捕获。

问题2:

既然捕获Exception是最方便的,那直接捕获Exception的父类Throwable是不是更方便?
首先,这样的做法是可以的,也确实更方便了,但是也有问题,因为try中永远只会抛出Exception的子类,而Throwable的子类不仅仅有Exception还有Error。所以,使用Throwable捕获到的异常会不是很明确。
在这里插入图片描述

关键字throws与throw的作用

throws的作用

在定义一个方法的时候可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而交给方法的调用处进行处理。
在这里插入图片描述
假设定义一个除法的方法div(),对于除法操作来说操作的时候可能出现异常也可能不出现异常,多以对于这样的方法最好将它使用throws关键字进行声明,一旦出现了异常,则应该交给调用处处理。

class Math{
	public int div(int i,int j) throws Exception{	// 定义除法操作,如果有异常,则交给被调用处处理
		int temp = i / j ;	// 计算,但是此处有可能出现异常
		return temp ;
	}
};
public class ThrowsDemo01{
	public static void main(String args[]){
		Math m = new Math() ;		// 实例化Math类对象
		System.out.println("除法操作:" + m.div(10,2)) ;
	}
};

在这里插入图片描述
因为div方法使用了throws关键字声明,所以在调用此方法的时候,必须进行异常处理。否则会出现编译时错误

class Math{
	public int div(int i,int j) throws Exception{	// 定义除法操作,如果有异常,则交给被调用处处理
		int temp = i / j ;	// 计算,但是此处有可能出现异常
		return temp ;
	}
};
public class ThrowsDemo01{
	public static void main(String args[]){
		Math m = new Math() ;		// 实例化Math类对象
		try{
			System.out.println("除法操作:" + m.div(10,2)) ;
		}catch(Exception e){
			e.printStackTrace() ;	// 打印异常
		}
	}
};

如果在主方法上也使用throws关键字声明,是不是意味着主方法也可以不处理异常?是否可行?

class Math{
	public int div(int i,int j) throws Exception{	// 定义除法操作,如果有异常,则交给被调用处处理
		int temp = i / j ;	// 计算,但是此处有可能出现异常
		return temp ;
	}
};
public class ThrowsDemo02{
	// 在主方法中的所有异常都可以不使用try...catch进行处理
	public static void main(String args[]) throws Exception{
		Math m = new Math() ;		// 实例化Math类对象
		//System.out.println("除法操作:" + m.div(10,2)) ;
		System.out.println("除法操作:" + m.div(10,0)) ;
	}
};

在这里插入图片描述
下属做事情出错,直属领导负责,这个领导负责不了进行上报,都处理不了都会逐级上报,异常处理也是这样的机制。

上面的代码中主方法不处理任何异常了,而是交给最大的头,JAVA中最大的头就是JVM,交给JVM处理了,在主方法使用throws关键字声明,则表示一切的异常交给JVM去处理,默认的处理方式也是JVM进行处理的,也就是不做任何异常处理的时候,默认就是如果出现了异常,是jvm直接去处理的。

throw的作用

throw关键字的作用是在程序中抛出一个异常。抛出的时候抛出的是一个异常类的实例化对象。

在异常的处理中,try语句中要捕获的是一个异常的对象,那么此异常对象也可以自己抛出。

public class ThrowDemo01{
	public static void main(String args[]){
		// 有异常了必须进行处理
			throw new Exception("自己抛着玩的。") ;	// 抛出异常的实例化对象
		}
	}
};

在这里插入图片描述

public class ThrowDemo01{
	public static void main(String args[]){
		try{
			throw new Exception("自己抛着玩的。") ;	// 抛出异常的实例化对象
		}catch(Exception e){
			System.out.println(e) ;
		}
	}
};

在这里插入图片描述
例子2:

class Math{
	public int div(int i,int j) throws Exception{	// 定义除法操作,如果有异常,则交给被调用处处理
		System.out.println("***** 计算开始 *****") ;
		int temp = 0 ;	// 定义局部变量
		try{
			temp = i / j ;	// 计算,但是此处有可能出现异常
		}catch(Exception e){  // 抛出异常,调用处会捕获这里抛出的异常
			throw e ;
		}finally{	// 不管是否有异常,都要执行统一出口
			System.out.println("***** 计算结束 *****") ;
		}
		return temp ;
	}
};
public class ThrowDemo02{
	public static void main(String args[]){
		Math m = new Math() ;
		try{
			System.out.println("除法操作:" + m.div(10,0)) ;
		}catch(Exception e){
			System.out.println("异常产生:" + e) ;
		}
	}
};

在这里插入图片描述
当有异常产生的时候,会先执行finally,执行完finally再返回方法调用处,在方法调用处处理该异常。
所以,使用throws声明的方法中的try–catch(throw e)—fially执行顺序是,try中捕获到了异常后执行catch抛出异常,然后执行finally,最后返回方法调用处,执行方法调用处的try-catch操作。
在这里插入图片描述

Exception与RuntimeException的区别

在这里插入图片描述
parseInt()方法声明时候抛出了NumberFormatException这个异常就是RuntimeException的子类。

public class RuntimeExceptionDemo01{
	public static void main(String args[]){
		String str = "123" ;	// 定义字符串,全部由数字组成
		int temp = Integer.parseInt(str) ; // 将字符串变为int类型
		System.out.println(temp * temp) ;	// 计算乘方
	}
};

问题:

parseInt()方法声明时候也使用throws抛出了异常,为什么可以不使用try-catch处理可以直接运行成功呢?不是说方法使用throws关键字声明以后,产生的异常会抛出给调用处需要在调用处处理,不管程序是否会发生都需要使用try--catch进行处理否则编译会报错提示必须捕获该异常“must be caught or decleared to be thrown”么?为什么这个例子没有try-catch捕获也没有报错直接运行成功了?

在这里插入图片描述
也就是说对于Exception的异常来说,如果不进行try---catch 处理程序直接中断执行,异常退出了。

但是对于RuntimeException的异常来说,可以不进行try--catch处理,这个过程不是硬性的要求,因为JVM默认会对RuntimeException的异常进行处理。
没有异常的时候程序正常执行,有异常发生后,jvm直接打印了该异常,程序也中断执行了。
所以总结来说:
对于Exception,就算程序没有发生异常,不try-catch处理编译直接回报错;
对于RuntimeException可以不使用try-catch进行捕获处理,当程序没有发生异常的时候,程序正常执行;当有异常发生以后程序抛出异常给了JVMjvm打印了该异常信息,程序中断执行了。所以对于RuntimeException的异常最好也使用try-catch进行处理。
在这里插入图片描述

ArithmeticException 算术异常也是RuntimeException。

自定义异常类

只要继承Exception类就可以实现自定义异常类。java中提供的都是标准异常,如果要定义自己的异常信息就可以自定义异常。
只要直接继承Exception类即可。

class MyException extends Exception{	// 自定义异常类,继承Exception类
	public MyException(String msg){
		super(msg) ;	// 调用Exception类中有一个参数的构造方法,传递错误信息
	}
};
public class DefaultException{	
	public static void main(String args[]){
		try{
			throw new MyException("自定义异常。") ;	 // 抛出异常
		}catch(Exception e){
			System.out.println(e) ;
		}
	}
}

在这里插入图片描述

断言

断言是在JDK1.4之后出现的,断言就是断定某一个操作的结果肯定是正确的,如果程序执行到出现断言语句的时候发现结果不正确了,则会出现错误的信息。
在这里插入图片描述

public class Test{
	public static void main(String args[]){
		int x[] = {1,2,3} ;	// 定义数组,长度为3
		assert x.length==0 ;	// 此处断言数组的长度为0
	}
};

在这里插入图片描述
没生效?是的。
断言本身不会影响程序的执行,但是如果想让一个断言起作用,则必须对断言进行验证:

-enableassertions  可以简写为-ea

验证上面的Test程序,java -ea Test 出现错误:
在这里插入图片描述

public class Test{
	public static void main(String args[]){
		int x[] = {1,2,3} ;	// 定义数组,长度为3
		assert x.length==3 ;	// 此处断言数组的长度为3,断言正确
	}
};

在这里插入图片描述
断言就是验证,上面的断言信息是java默认的断言信息,断言的错误信息也可以自定义:

public class Test{
	public static void main(String args[]){
		int x[] = {1,2,3} ;	// 定义数组,长度为3
		assert x.length==0 : "数组长度不为0" ;	// 此处断言数组的长度为0
	}
};

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值