异常:异常是指中断程序正常执行的一种指令流
在JAVA程序中一旦出现了异常,而程序又没有及时处理的情况下,那么程序会中断执行。
例如,观察以下的代码:
public class Demo22{
public static void main(String args[]){
int i = 10 ;
int j = 0 ;
System.out.println(" --------- 计算开始 ---------") ;
System.out.println("i / j = " + (i / j)) ; à 此段代码出现了异常
System.out.println(" --------- 计算结束 ---------") ;
}
};
以上代码编译的时候不存在任何的问题,那么执行时,出错了,打印内容如下:
--------- 计算开始 ---------
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Demo22.main(Demo22.java:6)
整个程序,在出现异常的代码之后不再被执行了,异常之前的程序呢?正确的执行了。
那么在JAVA中我们所处理的异常都属于运行时异常,即:执行JAVA程序的时候出现的错误,那么实际上对于JAVA的异常分类应该按如下的形式划分:
ArithmeticException à RuntimeException à Exception(往往是要由用户自己处理的)
所以对于异常而言,它是一个统称,代表了:
Throwable(可能的抛出)
|- Exception:表示需要人为处理的异常,指的是程序的错误 à 因为程序的错误较多,所以就习惯了把所有的错误都统一成为异常。
|- Error:表示JVM错误,人为不能处理
异常的处理格式如下:
try{
包含可能出现错误的代码段 ;
}catch(出错的类型 出错的对象){
对于错误的处理语句 ;
}
那么使用如上的格式修改之前的代码,保证程序可以正确的执行完:
public class Demo23{
public static void main(String args[]){
int i = 10 ;
int j = 0 ;
System.out.println(" --------- 计算开始 ---------") ;
try{
System.out.println("i / j = " + (i / j)) ;
}catch(ArithmeticException e){
System.out.println("计算出现了错误。。。") ;
}
System.out.println(" --------- 计算结束 ---------") ;
}
};
但是以上的程序依然存在了些小小的问题,例如:对于计算,往往应该由用户自己输入数据,所以此时可以通过接收参数为其输入数据。代码如下:
public class Demo24{
public static void main(String args[]){
int i = 10 ;
int j = 0 ;
System.out.println(" --------- 计算开始 ---------") ;
try{
i = Integer.parseInt(args[0]) ;
j = Integer.parseInt(args[1]) ;
System.out.println("i / j = " + (i / j)) ;
}catch(ArithmeticException e){
System.out.println("计算出现了错误。。。") ;
}
System.out.println(" --------- 计算结束 ---------") ;
}
};
如果现在输入的内容是正确的数字,则程序不会有任何的问题,但是既然数据是由用户自己输入的,那么肯定会输入各种违法的数据。
存在的问题:
· 不输入任何参数,出现数组越界:ArrayIndexOutOfBoundsException
· 输入的参数不是数字,出现了数字格式转换错误:NumberFormatException
· 输入的被除数是0,出现算术错误:ArithmeticException
在以上的错误之中,只有算术错误被处理了,因为在程序上具备了算术错误的处理能力。那么也就意味着,现在的异常处理并不完善,需要加入更多的处理,所以需要编写更多的catch。
以上的程序修改为:
public class Demo24{
public static void main(String args[]){
int i = 10 ;
int j = 0 ;
System.out.println(" --------- 计算开始 ---------") ;
try{
i = Integer.parseInt(args[0]) ;
j = Integer.parseInt(args[1]) ;
System.out.println("i / j = " + (i / j)) ;
}catch(ArithmeticException e){
System.out.println("算术错误。。。"+e) ;
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println("没有输入参数。。。"+e) ;
}
catch(NumberFormatException e){
System.out.println("输入的内容不是数字。。。"+e) ;
}
System.out.println(" --------- 计算结束 ---------") ;
}
};
但是会发现比较麻烦,因为现在已经知道了的是三个错误,那么对于很多未知道的错误呢?那么此时,就需要分析异常的产生过程。
发现catch中接收的内容都是对象,那么也就意味着,所谓的异常,就是自动产生了一个异常类的实例化对象。一出错就产生。
对象有一个特点,可以向上自动转型,Exception是用户需要处理的最大异常,那么证明所有的对象都可以向Exception转换。
public class Demo25{
public static void main(String args[]){
int i = 10 ;
int j = 0 ;
System.out.println(" --------- 计算开始 ---------") ;
try{
i = Integer.parseInt(args[0]) ;
j = Integer.parseInt(args[1]) ;
System.out.println("i / j = " + (i / j)) ;
}catch(ArithmeticException e){
System.out.println("算术错误。。。"+e) ;
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println("没有输入参数。。。"+e) ;
}
catch(NumberFormatException e){
System.out.println("输入的内容不是数字。。。"+e) ;
}
catch(Exception e){
System.out.println("其他异常。。。"+e) ;
}
System.out.println(" --------- 计算结束 ---------") ;
}
};
注意:
如果在程序中出现了多个catch语句,则捕获更粗的catch要放在捕获更细的catch之后。
public class Demo25{
public static void main(String args[]){
int i = 10 ;
int j = 0 ;
System.out.println(" --------- 计算开始 ---------") ;
try{
i = Integer.parseInt(args[0]) ;
j = Integer.parseInt(args[1]) ;
System.out.println("i / j = " + (i / j)) ;
}catch(Exception e){
System.out.println("其他异常。。。"+e) ;
}catch(ArithmeticException e){
System.out.println("算术错误。。。"+e) ;
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("没有输入参数。。。"+e) ;
}catch(NumberFormatException e){
System.out.println("输入的内容不是数字。。。"+e) ;
}
System.out.println(" --------- 计算结束 ---------") ;
}
};
则编译的时候出现了以下的错误,说是许多的异常已经被捕获了。
Demo25.java:14: 已捕捉到异常 java.lang.ArithmeticException
catch(ArithmeticException e){
^
Demo25.java:17: 已捕捉到异常 java.lang.ArrayIndexOutOfBoundsException
catch(ArrayIndexOutOfBoundsException e){
^
Demo25.java:20: 已捕捉到异常 java.lang.NumberFormatException
catch(NumberFormatException e){
^
3 错误
既然所有异常类的对象都可以向Exception转换,那么是不是直接使用Exception接收更方便?
public class Demo26{
public static void main(String args[]){
int i = 10 ;
int j = 0 ;
System.out.println(" --------- 计算开始 ---------") ;
try{
i = Integer.parseInt(args[0]) ;
j = Integer.parseInt(args[1]) ;
System.out.println("i / j = " + (i / j)) ;
System.out.println("***************************") ;
}catch(Exception e){
System.out.println(e) ;
}
System.out.println(" --------- 计算结束 ---------") ;
}
};
以上是异常处理的一种格式,实际上异常处理还有另外一种格式,就是说,可以为异常做一个统一的出口,不管是否发生了异常,都要执行此代码:
try{
包含可能出现错误的代码段 ;
}catch(出错的类型 出错的对象){
对于错误的处理语句 ;
}finally{
不管是否出现异常,都执行此代码 ;
}
代码如下:
public class Demo27{
public static void main(String args[]){
int i = 10 ;
int j = 0 ;
System.out.println(" --------- 计算开始 ---------") ;
try{
i = Integer.parseInt(args[0]) ;
j = Integer.parseInt(args[1]) ;
System.out.println("i / j = " + (i / j)) ;
}catch(Exception e){
System.out.println(e) ;
}finally{ à 典型的程序出口
System.out.println("不管是否存在异常,此代码都会被执行。。。") ;
}
System.out.println(" --------- 计算结束 ---------") ;
}
};
在异常处理中还有两个很重要的关键字
· throws:在方法的声明处使用,表示此方法不处理异常,而交给被调用处处理。
· throw:表示人为的抛出一个异常。
例如:定义一个数学类,里面有一个除法
class Math{
// 此代码有可能发生问题,也有可能不发生问题
// 一旦发生问题,找调用处,谁调用的此方法,谁去处理
public int div(int i,int j) throws Exception{
return i / j ;
}
};
public class Demo28{
public static void main(String args[]){
Math m = new Math() ;
System.out.println(m.div(10,2)) ;
}
};
按规定来说,此方法在调用的时候使用异常的捕获,如果不使用,则编译时出现以下的错误提示:
Demo28.java:11: 未报告的异常 java.lang.Exception;必须对其进行捕捉或声明以便抛出
System.out.println(m.div(10,2)) ;
^
1 错误
所以对于调用有throws声明的方法,必须使用try…catch:
class Math{
// 此代码有可能发生问题,也有可能不发生问题
// 一旦发生问题,找调用处,谁调用的此方法,谁去处理
public int div(int i,int j) throws Exception{
return i / j ;
}
};
public class Demo28{
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) ;
}
}
};
问?既然main方法是一个方法,那么能不能在主方法上编写throws语句呢?肯定是可以的
class Math{
// 此代码有可能发生问题,也有可能不发生问题
// 一旦发生问题,找调用处,谁调用的此方法,谁去处理
public int div(int i,int j) throws Exception{
return i / j ;
}
};
public class Demo29{
public static void main(String args[]) throws Exception{
Math m = new Math() ;
System.out.println(m.div(10,0)) ;
}
};
观察错误的提示:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Math.div(Demo29.java:5)
at Demo29.main(Demo29.java:11)
可以发现以上的错误提示与不使用try…catch效果是一样的,证明所有的错误都交给了JVM进行处理,实际上在JAVA中默认的处理方式也就是使用JVM完成。
throw:表示在程序中人为的抛出一个异常,而且必须使用try…catch进行处理。
public class Demo30{
public static void main(String args[]){
try{
throw new Exception("我自己乐意抛。。。") ;
}catch(Exception e){
System.out.println(e) ;
}
}
};
因为对于异常而言,最终结果肯定都是抛出一个异常的实例化对象。所以是自己抛还是系统抛都肯定需要进行异常的捕获及处理。
设计一个除法操作,在操作之前编写:计算开始,在操作之后编写计算结束,中间不管是否出现了错误,都要打印这样两句话,问:该如何实现?
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 Demo31{
public static void main(String artgs[]){
Math m = new Math() ;
try{
System.out.println(m.div(1,0)) ;
}catch(Exception e){
System.out.println(e) ;
}
}
};
一般而言,对于throw、throws、finally往往会一起使用。
自定义异常:
一个类只要继承了Exception就可以称为一个异常类。
class MyException extends Exception{
public MyException(String msg){
super(msg) ;
}
};
public class Demo32{
public static void main(String args[]){
try{
throw new MyException("自己定义玩的。。") ;
}catch(Exception e){
System.out.println(e) ;
}
}
};
注意点:
· throw与throws的区别?
|- throw:是人为抛出异常
|- throws:方法声明处使用,表示在方法中不处理异常
· final与finally
|- final:定义类、方法、常量
|- finally:异常的统一出口
写在最后:
码字不易看到最后了,那就点个关注呗,只收藏不点关注的都是在耍流氓!
关注并私信我“架构”,免费送一些Java架构资料,先到先得!