想像一下,你被安排去找一本指定的书这样一个任务,然后去阅读它并将其内容解释给班里面的学生们听。这个顺序可能是:

1.获得指定的书。

2.读它的内容。

3。将内容解释给班里的学生听。

但是,如果你不能够找到指定的书的话,接下来将会发生什么了?你接下来的工作将无法进展,因此你需要将你这一情况反馈给安排你任务的那个人。这个不希望的事件(书找不到)使你无法完成你的工作。通过将这一事件反馈出来,你想让这个请求的发起者采取补救或可选的措施。

接下来,让我们将上面的任务用代码来实现,我们定义一个teachClass,如下所示:

void teachClass() throws BookNotFoundException{
   boolean bookFound = locateBook();
   if(!bookFound)
    throw new BookNotFoundException();
   else{
    readBook();
    explainContents();
   }
  }

这个例子是用来比较throw 与 throws的语句。当执行throw new BookNotFoundException时, teachClass()终止执行。JVM将会创建BookNotFoundException的实力并且将它发送给teachClass()的调用者以便作出合理的处理。

throw语句被用于抛出exception的一个实例——BookNotFoundException. throws语句被用于标识teachClass可以抛出BookNotFoundException异常。

为什么一个方法选择抛出一个异常而不是自己处理这个异常呢? 这是方法的调用者和被调用者之间的一种契约。回到上面讲的teachClass方法,如果teachClass不能够找到指定的书的话,teachClass的调用者希望得到通知。teachClass方法自身不处理BookNotFoundException异常是因为他的责任不包括处理书找不到这一异常。

创建一个方法,使之抛出一个受控的异常(checked exception)

让我们来创建一个简单的方法,通过使用关键字throw和throws,它不能处理它自身抛出的checked exception。类DemoThrowsException定义了方法readFile,它包含了一个throws语句。真正抛出异常的是通过throw 语句完成的。




java怎样将throw 转换成返回值 java throw怎么用_java


throws语句用于表明该方法能够抛出一个FileNotFoundException类型的异常,

throw语句创建并抛出了FileNotFoundException类型的异常的对象。

一个方法可以包括多个用throws语句,但并不要求在throws语句中包含运行时异常和错误。一个方法仍能抛出抛出运行时异常或错误的实例而不需将他们包含在throws语句中。

使用一个方法来抛出一个checked exception

当你使用一个方法来抛出一个checked exception ,你能够 :

1.将那段代码放在try catch子块中并且捕获被抛出的异常。

2.在方法头中声明异常被重新抛出。

3.实现以上的组合。

在下面的例子中,方法useReadFile 将readFile方法的调用语句放在了try-catch块中。方法readFile抛出了FileNotFoundException(a checked exception):

java怎样将throw 转换成返回值 java throw怎么用_java怎样将throw 转换成返回值_02

 

你可以对上面的恶写法做出一点修改,如下:

java怎样将throw 转换成返回值 java throw怎么用_java_03

如果你在useReadFile方法中使用了以上的两种方法,useReadFile能够自己处理FileNotFoundException并且声明了他被抛出的异常,这种场景下,编译器也不会报错,如下所示:

java怎样将throw 转换成返回值 java throw怎么用_java_04

 

这个时候当readFile抛出FileNotFoundException时,将会使得这个异常有useReadFile中的catch块来捕获。

使用throw和throws语句的注意点:

1.没有必要在throws语句中包含runtime exception和错误。

如下代码所示:

java怎样将throw 转换成返回值 java throw怎么用_java_05

A处throws语句指定了这个方法可能抛出FileNotFoundException。

B处代码抛出了NullPointerException,但是他不包含在throws语句中。

C处代码创建并抛出FileNotFoundException实例。

将runtime exception 放在trows语句中也是有效的。如下代码所示:

public void readFile(String  file) throws NullPointerException,FileNotFoundException {
};

 不管你是否在throws语句中包含运行时异常和错误,一个方法总能够抛出运行时异常和错误。

2. 一个方法能够抛出throws语句中的异常的子类异常而不能抛出父类型的异常

因为IOException 是FileNotFoundException的弗雷,readFile不能抛出IOException类型的对象 。以下代码不正确,编译器将会报错:

 

class DemoThrowsException {
      public  void  readFile(String file) throws FileNotFoundException {
            boolean  found = findFile(file);
            if(!found)
                throw new IOException("Missing file");
           else {
            }
           boolean findFile(String  file){
           }
}

让我们对上面的代码做出正确性的修改 :

class DemoThrowsException {
      public  void  readFile(String file) throws IOException {
            boolean  found = findFile(file);
            if(!found)
                throw new FileNotFoundException("Missing file");
           else {
            }
           boolean findFile(String  file){
           }
}

一个方法即能够处理异常,同样也能够声明抛出的异常:

java怎样将throw 转换成返回值 java throw怎么用_编译器_06

 

从java7开始,在catch块中 你重新抛出异常所使用的变量类型可以是更加的通用,如下所示:

class GenericVariableTypeToRethrowException {
    public static void main(String args[]) 
                          throws IOException, SQLException {    #A
        String source = "DBMS";
        try {
            if (source.equals("DBMS")) throw new SQLException();
            else throw new IOException();
        }
        catch (Exception e) {            #B
            throw e;                    #C
        }
    }
}

在A处方法声明了IOException 和 SQLException。

在B处 变量e的类型是Exception比IOException 和 SQLException更通用。

在C处 catch块出重新抛出了捕获的异常 。

在try块中,代码throws要么有条件的抛出SQLException要么抛出IOException。在java7中,编译器能够决定catch块中所抛出的异常的具体类型并且能够重新的抛出它,即使是异常类型变量在异常的处理处是Exception——SQLException和IOException的父类。这在java7版本以前是不被允许的。

 

总之,通过throw能够抛出一个你定制的异常对象,这个异常对象由谁来处理,可以通过与throws和catch配合来处理。throws用来将这个异常抛出给调用它的上一层方法来处理。catch则可以在本方法内来对这个异常进行处理,同样也能够在catch块中将这个异常抛出,抛给上一层调用方法来处理。