Java核心API之异常处理(中)
1、throw关键字的使用
如果程序发生的错误无法处理或者无法捕获,会抛出错误异常对象。或者,程序员自行抛出异常,例如将异常抛出,让调用者捕获异常和处理。若想要自行抛出异常,我们可以使用“throw”关键字来将异常抛出。
示例代码如下:
/*
* 使用throw关键字自行抛出异常
*/
@Test
public void testThrow(){
String str = null;
try {
String subStr = str.substring(0);
} catch (Exception e) {
throw new RuntimeException("空指针异常");
}
}
分析:我们使用throw自行抛出我们想要的异常,当然还可以抛出自定义的异常,自定义异常我们下节继续讲解。
注意:小编的代码示例中抛出的是非检查异常(RuntimeException),所以方法上可以不用抛出异常。如果是自行抛出的是检查异常,方法上要使用throws关键字抛出异常。下面介绍java处理机制中throws关键字。
2、throws关键字的作用
我们编写的程序中有许多方法,其中有些方法可能抛出异常,但是有些异常不该当前方法捕获和处理应该继续抛出,而应该调用者来统一处理异常,这时需要使用throws关键字来声明这个方法。
示例代码片段如下:
/*
* 使用throws关键字抛出异常
*/
@Test
public void testThrows() throws IOException{
FileInputStream fis = new FileInputStream("test.txt");
int d= -1;
while((d=fis.read())!=-1){
System.out.println(d);
}
}
注意:小编之前写的许多代码例子都是没有处理异常,而是直接抛出异常。
分析:如果方法内部的业务逻辑产生的异常最好try-catch,如果是调用者经常调用的方法,可以将异常抛给调用者处理。
3、继承父类后重写方法时对throws的处理
子类继承父类后,父类的某个方法上声明了throws抛出异常,子类在重写该方法时必须注意以下几点:
1、父类throws抛出的异常可以不做任何处理;
2、可以抛出父类throws异常对象的部分异常;
3、可以抛出父类throws异常对象的子类异常;
4、不可以超出父类throws额外对象的异常;
5、不可以抛出父类throws异常对象的父类异常;
以上总结看上去很拗口,下面请看示例代码进行一一讲解:
public class Father {
private String face;
private int height;
private String habits;
public Father() {
}
public void talk(byte[] conent) throws IOException,NullPointerException {
String sayConent = new String(conent);
if(sayConent.length()>30){
throw new IOException("说话出现口吃");
}else if(sayConent.length()<=30&&sayConent.length()>0){
System.out.println("说话正常");
}else{
throw new NullPointerException("说不出来话");
}
}
}
class Son extends Father{
//父类throws抛出的异常可以不做任何处理
public void talk(byte[] conent){
String sayConent = new String(conent);
System.out.println("说出"+sayConent+"的话");
}
//可以抛出父类throws异常对象的部分异常
public void talk(byte[] conent) throws NullPointerException{
String sayConent = new String(conent);
if(sayConent.length()<0){
throw new NullPointerException("说不出来话");
}
}
//可以抛出父类throws异常对象的子类异常
public void talk(byte[] conent) throws UnsupportedEncodingException {
String sayConent = new String(conent,"UTF-8");
System.out.println("说出"+sayConent+"的话");
}
//不可以超出父类throws额外对象的异常
public void talk(byte[] conent) throws SQLException{
throw new SQLException("彻底说不出来话");
}
//不可以抛出父类throws异常对象的父类异常
public void talk(byte[] conent) throws Exception{
throw new Exception("彻底说不出来话");
}
}
注意:拷贝上述代码了解继承父类后重写方法时对throws的处理过程。
4、RuntimeException非检查异常
Java异常可以分为可检查异常,非检查异常:
可检查异常:可检查异常需要经过编译器验证,对于声明抛出异常的任何方法,编译器将强制执行处理或声明规则,不捕捉这种异常,编译器显示报错,编译不允许通过。
非检查异常:非检查异常不遵循处理或声明规则。在产生此类异常时,不一定非要采取任何适当操作,编译器不会检查是否已经解决了这个异常。
为了更好的解释上述定义,见下面代码:
1、处理检查异常:
/*
* 处理检查异常有两种方式:
* 1、捕获异常
* 2、抛出异常
*/
public void testCheckException() throws FileNotFoundException {
/*
* 构造方法FileInputStream()抛出FileNotFoundException
* FileNotFoundException是检查异常,这种异常不能逃过编译器的法眼
* 处理这种异常必须捕获或抛出
*/
//捕获异常
try {
FileInputStream fis = new FileInputStream("speech.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//抛出异常
FileInputStream fis2 = new FileInputStream("speech.txt");
}
2、理解检查异常和规避这类异常
/*
* NullPointerException是非检查异常,为什么编译器没有报错?
* 原因是非检查异常是很常见的异常,可能为了提高编译器的工作效率,像这种经常出现的异常,编译器“懒的管”。
* 非检查异常是程序员经常遇到的异常,作为一名合格的程序员必须有能力规避这种异常。
* 也可以理解为这是编译器或者说Java设计者对开发人员的期望吧。
*/
public void testUnCheckException(){
String str = null;
str.charAt(0);
//可以这样规避这类异常
String str;
str != null?str.charAt(0) : "";
}
注意:作为一名合格的程序员,应具备规避非检查异常的能力。
5、常见的RuntimeException有
1、NullPointerException异常
当对象的引用为null时,该引用调用该对象的成员或属性时,抛出该异常。
2、IllegalArgumentException
当向某个方法传入一个不合法或不正的参数时,抛出该异常。
3、NumberFormatException
当程序试图将字符串转换成一种数值类型,但该字符串不能转为适当格式时,抛出异常。
4、ArrayIndexOutOfBoundsException
当使用的数组下标超出数组允许范围时,抛出该异常。