java中的异常类Exception

异常的定义和使用方法咱就不说了,说点别的,有用的或者好玩的。

一、为什么要处理异常:
异常是导致程序中断运行的一种指令流,如果程序中有异常且不做任何处理的话,程序运行到异常处就会中断执行,直接结束程序,并将错误报告给用户。异常之后的语句也不再执行。为了保证程序的正常、完整运行,需要对异常进行处理。

二、Exception和Error:
Java的异常体系中,最常用的就是Exception和Error,他们都是Throwable的子类。
Exception:一般值程序中出现的问题,可以使用try…catch进行处理,例如经常见到的Exception的子类:NullPointerExcetion,ArrayIndexOutOfBoundsException,NumberFormatException等
Error:一般指JVM错误,程序中无法处理,如内存溢出问题。

三、Java的异常处理机制:
处理机制:程序运行的过程中发生异常,JVM会根据异常的类型产生一个异常类的实例化对象,然后在try语句中对此异常对象进行捕捉,并将该对象与catch语句中的各个异常类型进行匹配,如果匹配成功则执行catch语句中的处理程序。
因为Exception是所有异常类的父类,所以当第一个catch语句定义成Exception类型时,所有的异常将会直接走该catch而不会走下面其他的catch语句,即便其他catch中的异常类型与当前类型一致,因此当定义了Exception的catch语句又定义了其他的异常类型时,Exception的catch语句最好放在最后面,即:捕获更粗的异常要放在捕获更细的异常之后。
问题:既然更粗的类型可以捕获更多的异常,为什么不直接使用Throwable??
原因有二:
1、在平常的开发中,Exception中定义的类型基本上可以满足开发需求,没有必要使用Throwable;
2、 Throwable中不光有Exception还有Error,对于Error我们是无能为力的。

个人说明:有时候在开发中会碰到这样一个问题:代码一执行到某行,就直接跳转到catch语句中了,且报出的异常信息莫名其妙,但查看报错的代码行根本看不出来有问题甚至会觉得这就是一句类似于1+1=2的代码,很不理解为什么这样子的代码还会报错。
其实代码本身没有错。可以将catch中的异常类型由Exception改成Throwable,然后再打印输出异常信息,这时候的异常信息才是导致代码错误的真正原因。原因一般都是导入的jar包有冲突,替换jar就可以解决问题。

四、Throws和Throw关键字:
Throws:通过放在方法后面,声明该放方法不处理异常需要调用出自己处理,且告知方法抛出调用出需要处理的异常类型。
Throw:通常放在方法中,在程序中抛出一个异常,且抛出的是异常类的实例化对象。
由两者的定义可知:Throws抛出的是异常类,Throw抛出的则是异常类的实例。
另外,若是main方法也抛出异常,即:public static void main(String[] args) throws Exception,那么处理该异常的将会是JVM,也就是调用main方法的Java虚拟机,JVM使用默认的处理方式处理main方法抛出的异常,即中断代码的执行。

实例验证:
要求:设计一个相除的方法,但是在操作之前必须打印“计算开始”字样,且结束之后打印“计算结束”字样。如果计算过程中有异常的话,需要将异常交给调用处处理。
思路:
1、定义除法方法div(int i,int j),进行简单的除法操作:i/j。考虑到传入的j有可能会是0,所以添加try、catch代码块进行捕捉。要求中的打印“计算开始”字样可以放在i/j之前的try模块中,而代码执行的过程中可能也可能不会出现异常,为保证系统一定打印出“计算结束”字样,将System.out.println(“计算结束”);放到finally模块中。当出现异常时,需要将异常交给调用出进行处理,所以catch中不能进行异常处理,而只能将异常抛出,即throw e,因此div方法中也需要标记为throws Excepion。那么,除法代码应该如下:

class Math{
	public int div(int i,int j) throws Exception{//div方法抛出Exception类
		int temp=0;
		try{
			System.out.println("计算开始");
			temp=i/j;//进行除法计算
		}catch(Exception e){
			throw e;//抛出Exception的实例e
		}finally{
			System.out.println("计算结束");
		}
		return temp;//返回结果
	}
}

 2、使用main方法调用上面的div方法,因为有异常抛出所以需要处理。那么,代码应该如下:

public static void main(String[] args){
	Math math = new Math();
	int result=0;
	int result2=0;
	try{
		result = math.div(10,5);//正常数据测试
		System.out.println("10/5="+result);
		System.out.println("------------------------");
		result2  = math.div(10,0);//有异常的数据测试
		System.out.println("10/0="+result2);
	}catch(Exception e){
		System.out.println("发生异常了,异常为:"+e);
	}
}

3、为了验证“无论异常是否发生,catch之后没有写在finally中的语句是否执行”,在main方法的最后添加代码:System.out.println("------------------------------\n无论异常与否这句话还是会输出");因此完整代码为:

class Math{
	public int div(int i,int j) throws Exception{//div方法抛出Exception类
		int temp=0;
		try{
			System.out.println("计算开始");
			temp=i/j;//进行除法计算
		}catch(Exception e){
			throw e;//抛出Exception的实例e
		}finally{
			System.out.println("计算结束");
		}
		return temp;//返回结果
	}
}

public class ExceptionDemo{
	public static void main(String[] args){
		Math math = new Math();
		int result=0;
		int result2=0;
		try{
			result = math.div(10,5);//正常数据测试
			System.out.println("10/5="+result);
			System.out.println("------------------------");
			result2  = math.div(10,0);//有异常的数据测试
			System.out.println("10/0="+result2);
		}catch(Exception e){
			System.out.println("发生异常了,异常为:"+e);
		}
		System.out.println("------------------------------\n无论异常与否这句话还是会输出");
	}
}

4、执行结果:

5、程序的执行流程为:

 五、Exception与RuntimeException:
两者的区别如下:
Exception在程序中必须使用try…catch进行处理,如果不处理出现异常时程序会被JVM强制中断。
RuntimeException:可以不使用try…catch进行处理,但是如果有异常产生,那么异常将由JVM采用默认的处理方式即中断程序的执行自动进行处理。
简单实例:

public class RuntimeExceptionDemo{
	public static void main(String[] args){
		String str="123";
		int temp = Integer.parseInt(str);
		System.out.println(temp*temp);
	}
}

以上的代码看起来没有问题,运行起来也没有问题。但是Integer.parse()是有异常抛出的。这是JDK上parseInt方法的说明:

扫描二维码关注公众号,回复: 672254 查看本文章

public static int parseInt(String s) throws NumberFormatException
它抛出了NumberFormatException,也就是数字转换异常。
在平常的开发中,若是某个方法抛出异常,调用处必须捕获该异常或者将异常继续往上抛出,否则程序将报错。但是上面的代码既没有捕获也没有抛出却执行正确,就是因为它是RuntimeException,即运行时异常。
异常分为两种,一种是编译时异常,另一种就是运行时异常了。编译时异常在写代码的时候就知道会出现什么异常,譬如在处理文件流时的I/O问题、文件找不到的问题,你一new File(filePath)IDE就会提醒你这一块儿有异常,问你try/catch处理还是直接throws。要是即不try也不Throws,那么在编译的时候就会直接报错,强制你处理。运行时异常在编写代码的时候不会出现,自然IDE也不会提醒你处理,编译的时候也不会报错,但是在运行的时候若参数有问题或其他原因会导致异常的出现,如例子中的若输入字母就会报NumberFormatException。

六、断言(assert):
定义:断言就是断定某一个操作的结果肯定是正确的,如果程序执行到出现断言语句的时候结果不正确了,那么通过断言检查会为用户提示错误的信息。
定义格式:
Assert boolean表达式;
Assert boolean表达式:自定义的错误提示信息

如下面的例子:

public class TestAssert{
	public static void main(String[] args){
		int i[]={1,2,3};
		assert i.length==0;
	}
}

很明显,i.length=3而不是等于0,在编译并执行以后没有出现任何结果。如图:

那么如何让它处结果也就是起作用呢?可以使用enableassertions。其结构和定义如下:
-enableassertions[:<packagename>...|:<classname>]
               enable assertions
重新验证看看结果:

以上的错误信息是系统默认的,要是觉得不好不能表达准确的错误信息,咱们可以自己定义。如:

public class TestAssert{
	public static void main(String[] args){
		int i[]={1,2,3};
		assert i.length==0:"数组长度错误";
	}
}

 再进行编译验证:

这样的提示是不是清楚明了多了???

猜你喜欢

转载自1017401036.iteye.com/blog/2285130