标签:
异常:异常是导致程序中断运行的一种指令流,如果不对异常进行正确处理,则可能导致程序的中断执行,造成不必要的损失,所以在程序的设计中必须考虑各种异常的发生,并正确的做好相应的处理,这样才能保证程序的正常运行。
进行异常处理的目的?
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("********** 计算结束 ***********") ; } };
在计算机的发展史有两大杀手:断电、被除数为0
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("********** 计算结束 ***********") ; } };
程序的执行流程
以上的操作代码中只使用了基本的异常处理格式:try...catch, try中捕获异常,出现异常之后的代码将不再被执行,而是跳转到相应的catch中执行,用于处理异常。
当然对于异常也可以设置统一的出口,使用finally完成。
public class ExceptionDemo03{ 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) ; }finally{ // 作为异常的统一出口 System.out.println("不管是否出现异常,都执行此代码") ; } System.out.println("********** 计算结束 ***********") ; } };
修改代码,通过初始化参数,输入i和j的值
public class ExceptionDemo04{ 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) ; } System.out.println("********** 计算结束 ***********") ; } };输入合法的参数:10 2
此时的数据实际上是交给用户输入的,既然是用户输入,就有可能输入不正确,实际上以上的代码出现了三个问题:
1、如果没有输入参数或者输入的参数不够,就会出现问题:
数组超出绑定,因为没有输入参数
2、如果现在输入的时候输入的参数不是数字,而是字母;
3、算术异常,如果被除数为0的话
所以以上程序产生了三个比较明显的异常:
数组超出绑定:ArrayIndexOutOfBoundsException
数字格式化异常:NumberFormatException
算术异常:ArithmeticException
如果想要程序执行正确,则必须同时对三个异常进行处理,所以此时就需要三个catch语句。
public class ExceptionDemo05{ 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) ; } System.out.println("********** 计算结束 ***********") ; } };
异常的继承结结构:
在整个java的异常结构上,实际上有以下两个最常用的类:Exception、Error,这两个类都是Throwable的子类。
Exception:一般表示的是程序中出现的问题,可以直接使用try...catch处理。
Error:一般指的是JVM错误,程序中无法处理。
一般情况下开发者都比较习惯将Error和Exception统称为异常,而之前处理的若干异常,都是Exception的子类。
注意:
一般在输出异常信息的时候,可以直接使用System.out.println()打印异常对象。
也可以通过Exception提供的一个方法:public void printStackTrace()
Java中的异常处理机制
在整个java的异常处理中,实际上也是按照面向对象的方式进行处理,处理的步骤如下:
一旦产生异常,则首先会产生一个异常类的实例化对象:
在try语句中对此异常对象进行捕捉:
产生的异常对象与catch语句中的各个异常类型进行匹配,如果匹配成功,执行catch语句中的代码。
回顾对象的多态性:子类的实例化对象可以直接使用父类的对象进行接收。
实际上在异常处理中也是使用此种概念,因为try中产生的是一个实例化对象。如果现在有一些其他的异常不知道的话,则可以最后使用Exception进行捕获。
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("********** 计算结束 ***********") ; } };
比如如下程序就是错误的
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){ // 捕获算术异常 // System.out.println("算术异常:" + e) ; e.printStackTrace() ; } System.out.println("********** 计算结束 ***********") ; } };
既然所有的Exception对象都可以使用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进行捕获。当然,在一个比较细致的开发中是不建议这样使用的,所有的异常最好分别捕获。
问题:
既然捕获Exception是最方便的,那么直接捕获Throwable不就行了?
首先,这样的做法是可以的,但是正常的开发人员是不会这样做的,因为在程序中的try中永远只会抛出Exception的子类,而Throwable中不光有Exception还有Error。
异常概念的总结:
1、异常出现之后,如果没有合理的处理的话,则会让整个程序中断执行。
2、使用try...catch和try...catch...finally可以处理异常,finally将作为异常的统一出口,不管是否有此异常都会执行此语句。
3、一个异常处理中可以同时出现多个catch,但是捕获更粗的异常要放在更细的异常之后,否则程序编译时将出现错误。
4、在异常中最大的类是Throwable,分为两个子类:Exception、Error。
Exception:是程序可以自己处理的异常。
Error:表示JVM错误,一般程序无法处理。
5、捕获的时候可以直接捕获Exception,但是最好分开捕获,如果所有的异常后的处理操作都是一样的话,则也可以直接捕获Exception。
6、每当异常产生后,会在程序中产生一个异常类的实例化对象,之后使用此对象与catch中的异常类型相匹配,如果匹配成功吗,则执行catch语句中的内容,如果匹配不成功,则继续向下进行匹配,如果都无法成功,程序中出现中断执行的问题。
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,0)) ; }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,0)) ; } };
throw关键字:
throw关键字的作用是在程序中抛出一个异常。抛出的时候抛出的是一个异常类的实例化对象。
与throws不同的是,可以直接使用throw抛出一个异常。抛出的时候直接抛出异常类的实例化对象即可。
在异常的处理中,try语句中要捕获的是一个异常的对象,那么异常对象也可以自己抛出。
public class ThrowDemo01{ public static void main(String args[]){ try{ throw new Exception("自己抛着玩的。") ; // 抛出异常的实例化对象 }catch(Exception e){ System.out.println(e) ; } } };
在一般的开发中try...catch...finally、throw、throws联合使用的情况是最多的,例如:现在要设计一个相除的方法,但是在进行操作之前必须打印“计算开始”信息、结束之后必须打印“异常结束”的信息,如果有异常的话则应该把异常交给调用处处理,面对这样的要求,就必须使用以上的全部操作。
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代码块内是不会执行的。
Exception与RuntimeException的区别
是一个在JAVA面试中经常出现的一个问题
观察以下代码:
public class RuntimeExceptionDemo01{ public static void main(String args[]){ String str = "123" ; // 定义字符串,全部由数字组成 int temp = Integer.parseInt(str) ; // 将字符串变为int类型 System.out.println(temp * temp) ; // 计算乘方 } };parseInt()方法定义格式:
public static int parseInt(String s) throws NumberFormatException在此方法中明明使用了throws关键字抛出异常,为什么不用处理,编译也可以通过呢?
Exception与RuntimeException
这两个类的区别如下:
Exception在程序中是必须使用try...catch进行处理
RuntimeException可以不用try...catch进行处理,但是如果有异常产生,则异常将由JVM进行处理。
在java的异常处理机制中:
如果抛出的是Exception的类型,则必须使用try...catch进行处理。
如果抛出的是RuntimeException的类型,则不是必须使用try...catch进行处理,一旦发生异常之后将由JVM进行处理,但是为了保证程序的健康性,建议在有可能出现异常的地方还是老实的使用try...catch进行处理。
自定义异常类:
只需要继承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) ; } } }
断言:(assert)
在JDK1.4之后,java中增加了断言的功能,那么什么叫断言呢?断言就是肯定某一个结果的返回值是正确的,如果最终此结果的返回值是错误的,则通过断言检查肯定会为用户提示错误信息。断言的定义格式如下所示:
assert boolean 表达式;
assert boolean 表达式:详细的信息;
public class Test{ public static void main(String args[]){ int x[] = {1,2,3} ; // 定义数组,长度为3 assert x.length==0 : "数组长度不为0" ; // 此处断言数组的长度为0 } };
断言本身不会影响程序的执行,但是如果想让一个断言起作用,则必须对断言进行验证。
断言验证方式如下:
在DOS命令下编译后 使用java -ea Test即可在MyEclipse中验证步骤:选中程序,右键Run as—>Run configurations—>VM arguments 中添加-ea即可。
总结:
1、断言在实际开发中并不是很常见,简单了解即可。
2、throw和throws关键字联合使用问题
throw:抛出异常对象
throws:在方法的声明处使用,表示此方法不处理异常。
3、Exception的异常时必须处理的,而RuntimeException的异常是可以不处理的,但是为了保证程序的运行,只要有异常最好全部处理。
4、如果需要自定义异常,则直接继承Exception类即可
标签:
原文地址:http://blog.csdn.net/u013087513/article/details/51155619