4-使用throw抛出异常
1.抛出异常
(1)如果需要在程序中自行抛出异常,则应该使用throw语句,throw语句可以单独使用,throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例;
(2)throw语句如果抛出的异常是Checked异常,则该throw语句要么处于try块中,显式捕获该异常,要么放在一个带throws声明抛出的方法中,即把该异常交给方法的调用者处理;如果throw语句抛出的异常是Runtime异常,则该语句无须放在try块里,也无须放在throws声明的方法中;程序可以显式使用try..catch来捕获并处理该异常,也可以完全不理会异常,把异常交给调用者处理;
public class Test7 { public static void main(String[] args) { try{ //调用声明抛出Checked异常的方法,要么显式捕获该异常 //要么在main方法中再次声明抛出 throwChecked(-3); }catch(Exception e){ System.out.println(e.getMessage()); } //调用声明抛出Runtime异常的方法既可以显式捕获该异常 //也可以不理会该异常 throwRuntime(3); } public static void throwChecked(int a) throws Exception{ if(a>0){ //自行抛出Exception异常 //该代码必须处于try...catch块中,或处于带throws声明的方法中 throw new Exception("a的值大于0,不符合要求"); } } public static void throwRuntime(int a){ if(a>0){ //自行抛出RuntimeException异常,既可以显式捕获该异常 //也可完全不理会该异常,把该异常交给该方法的调用者处理 throw new RuntimeException("a的值大于0,不符合要求"); } } }
2.自定义异常类
(1)用户自定义异常都应该继承Exception基类,如果希望自定义Runtime异常,则应该继承RuntimeException异常基类。
(2)定义异常类时通常需要提供两个构造器,一个无参构造器,一个带有字符串参数的构造器,这个字符串将作为该异常对象的描述信息,即getMessage()方法的返回值;
public class MyException extends Exception{ //无参数构造器 public MyException(){ } //带一个字符串参数的构造器 public MyException(String msg){ super(msg); } }
3.catch和throw同时使用
(1)多个方法协同处理同一个异常的情形,可以在catch块中结合throw语句来完成:
public class AuctionTest { private double initPrice = 30.0; //因为该方法中显式抛出了AuctionException异常 //所以此处需要声明抛出AuctionException异常 public void bid(String bidPrice)throws MyException{ double d = 0.0; try{ d = Double.parseDouble(bidPrice); }catch(Exception e){ //此处完成本方法中可以对异常执行的修复处理 //此处仅仅是在控制台打印异常的跟踪栈信息 e.printStackTrace(); //再次抛出自定义异常 throw new MyException("竞拍价格必须是数值,不能包含其他字符"); } if(initPrice > d){ throw new MyException("竞拍价比起拍价低,不允许竞拍"); } initPrice = d; } public static void main(String[] args) { AuctionTest at = new AuctionTest(); try{ at.bid("df"); }catch(MyException e){ //再次捕获到bid()方法中的异常,并对该异常进行处理 System.out.println(e.getMessage()); } } }
4.throw语句增强
有如下代码:
try{
new FileInputStream("a.txt");
}catch(Exception e){
e.printStackTrace();
throw e; //再次抛出捕获到的异常
}
Java7以前,因为捕获到异常时声明的异常类型为Exception,所以在再次抛出异常时抛出的异常同样为Exception异常:
public staic void main(String args[])
throws Exception //Java6认为可能抛出Exception异常
{
try{
new FileInputStream("a.txt");
}catch(Exception e){ //声明捕获到的异常为Exception异常
e.printStackTrace();
throw e; //声明捕获的异常是Exception 再次抛出的异常同样为Exception
}
}
从java7开始,编译器会自行检查throw语句抛出异常的实际类型:
public staic void main(String args[])
throws FileNotFoundException //Java7编译器检查后,只需抛出FileNotFoundException异常
{
try{
new FileInputStream("a.txt");
}catch(Exception e){ //声明捕获到的异常为Exception异常
e.printStackTrace();
throw e;//声明捕获的异常是Exception 编译器检查后实际上的异常为FileNotFoundException异常
}
}
5.异常链
(1)把底层原始异常直接传给用户是一种不好的表现,通常做法为:程序先捕获原始异常,然后抛出一个新的业务异常,新的业务异常包含对用户的提示信息,这种处理方式被称为异常转译;
(2)把原始异常隐藏起来,仅仅向上提供必要的提示信息的处理方式,可以保证底层异常不会扩散到表现层。