throw,意思是「投擲、拋、丟」。 Throw、Throws和Throwable三者都用於異常處理。
Throwable在Java中是異常處理這個分支的頂級父類,其它所有異常處理的實作都依賴Throwable
開啟Java官方文件( Java8版本),找到Throwable,它的直接子類別為Error和Exception。
Error和Exception兩者的特點在於Error異常程式無法處理,只能交由人工介入修改程式碼,例如堆疊溢出、堆疊溢出等等;而Exception異常可提前發覺,並作出有效處理。
在Error中,常見的有堆疊溢位和堆疊溢位等等。
舉個例子,StackOverflowError
public class ErrorTest { public static void main(String[] args) { main(args); } }
無限遞歸,執行這個程式就會報到堆疊溢位例外。
再例如堆異常,OutOfMemoryError
public class ErrorTest { public static void main(String[] args) { Integer[] testArray = new Integer[1024*1024*1024]; } }
在Exception中就有非常多我們所熟知的異常情況了,像是NullPointerException(空指標異常)、ArrayIndexOutOfBoundsException(陣列下標越界)、NumberFormatException(數位格式化例外)等等。
public class ExceptionTest { public static void main(String[] args) { int[] testArray = null; System.out.println(testArray[0]); //空指针异常 } }
public class ExceptionTest { public static void main(String[] args) { int[] testArray = new int[3]; System.out.println(testArray[3]); //数组下标越界 } }
public class ExceptionTest { public static void main(String[] args) { String num = "abc"; System.out.println(Integer.parseInt(num)); //数字格式化异常 } }
throws應用在方法宣告處,指明此方法執行時可能會出現的例外類型。一旦該方法執行時出現異常,就會在異常代碼處產生一個異常類別的對象,此對象滿足Throws後的異常類型時,就會被拋出。這裡有兩個過程,程式碼有異常時
1. 產生一個異常物件;
2. throws捕獲到這個異常,將異常物件拋出
throws和try-catch-finally一起稱為異常處理的兩種方式。
try-catch-finally是在出現異常時主動處理掉異常,使得程式可以繼續執行下去;而throws捕獲到異常之後向上拋出異常對象,不去真正地處理這個異常。
所謂向上拋出異常對象,是將例外物件交給呼叫者去處理,例如方法A呼叫方法B,B透過throws拋出異常,而A可以選擇使用try-catch-finally處理掉異常,也可以透過throws繼續向上拋出異常對象,直到異常被真正處理掉。如果一直沒有方法去處理異常,異常物件最終會被拋給JVM,導致程式停止運作。
@Test public void throwsTest(){ //调用者解决抛出的异常 try{ formatChange("abc"); } catch (NumberFormatException e){ System.out.println("转换格式错误!"); } catch (Exception e){ System.out.println("出现错误"); } } private int formatChange(String str) throws NumberFormatException{ //出现异常向上抛出 return Integer.parseInt(str); }
——如何選擇try-catch-finally還是throws?
當一個方法中存在異常需要處理,在大多數情況下,既可以選擇try-catch-finally直接處理掉這個異常,也可以選擇throws向上拋出異常,交給呼叫者去處理(異常拋到最後,總要有一方真正地去處理這個異常,怎麼處理?還是用try-catch-finally唄),在選擇上比較自由,但是,出現以下兩種情況時,需要遵循一定的規則(如有補充,請指出)。
如果父類別中被重寫的方法沒有使用throws拋出異常,則子類別重寫的方法也不能使用throws拋出異常,也就意味著這種情況必須使用try-catch-finally去處理。
在方法A中,先後呼叫了另外的幾種方法,這幾種方法是遞進關係執行的且其中許多方法都存在異常需要處理,這種情況建議被呼叫的幾個方法使用throws向上拋出異常,在方法A中,使用try-catch-finally統一處理掉這些異常。
針對第一條,這是一個規定,子類別中重寫的方法使用throws拋出的異常必須不大於父類別中被重寫的方法拋出異常的範圍。舉個例子,父類別中的方法B拋出NullPointerException異常,則子類別中重寫B方法就不能拋出如Exception這種比NullPointerException範圍更大的異常;如果父類別中被重寫的方法沒有拋出任何異常,則子類別更不能拋出異常。
為什麼?展示一段程式碼。
//假设父类中的方法B抛出NullPointerException异常,子类中的方法B可以抛出Exception private void test(ParentClassTest parent){ try{ parent.B(); } catch(NullPointerException e){ System.out.println("出现了空指针异常"); } }
在本範例中,假設父類別中的方法B拋出NullPointerException異常,子類別中重寫的方法B可以拋出Exception。那麼傳進給test方法的參數如果是父類別的實例化對象,那麼呼叫test方法就沒有任何問題。如果傳進的參數是子類別的實例化對象,再去呼叫子類別重寫的方法B,那麼就有可能拋出Exception異常,try-catch結構就壓不住這個異常了,這顯然是一個不合理的操作。
针对第二条,假设方法A中调用了方法C、D、E,这三个方法都有可能产生异常,且存在递进关系,也就是D、E执行需要C执行完成、E执行依赖C、D执行完成。那么就推荐在C、D、E中向上抛出异常,在方法A中集中处理。为什么?如果C、D、E都是向上抛出异常,而A使用try-catch-finally去处理这个异常,如果某个方法真的出现异常,则不再继续执行。而如果C、D、E都使用try-catch-finally直接解决掉异常,那么即使产生了异常,方法A也不会接收到异常的产生,那么还会接着往下执行,但是C出现了异常,再执行D、E没有任何意义。
如果在程序编写时有手动抛出异常的需求,则可以使用throw
throw使用在方法体内。与try-catch-finally和throws都不同,异常处理的两个阶段:1.遇到异常,生成异常对象;2.捕获到异常,进行抛出或处理。try-catch-finally和throws都处在第二个阶段,都是捕获到异常后的相关处理,一般使用系统根据异常类型自动生成的异常对象进行处理。而throw应用在第一阶段,手动地产生一个异常对象。
举一个例子,判断一个数值是否为非负数,如果为负数,则抛出异常。
class ThrowTest{ private int Number; public void judge(int num){ if(num>=0){ this.Number = num; } else{ throw new RuntimeException("传入参数为负数"); } } }
@Test public void test2(){ ThrowTest throwTest = new ThrowTest(); throwTest.judge(-100); }
成功抛出异常。
使用try-catch捕获一下异常。
@Test public void test2(){ ThrowTest throwTest = new ThrowTest(); try{ throwTest.judge(-100); } catch (RuntimeException e){ System.out.println(e.getMessage()); } }
如果把throw抛出的异常改为Exception,则直接报错,也就是不能编译。Exception包含两种异常:编译时异常和运行时异常,前者在编译前就要检查是否有可能产生编译时异常;后者是在编译后运行时才会判断的异常。而throw new Exception包含了编译时异常,需要显式处理掉这个异常,怎么处理?try-catch-finally或者throws
class ThrowTest{ private int Number; public void judge(int num) throws Exception{ if(num>=0){ this.Number = num; } else{ throw new Exception("传入参数为负数"); } } }
调用方也要随着进行更改。
@Test public void test2(){ ThrowTest throwTest = new ThrowTest(); try{ throwTest.judge(-100); } catch (RuntimeException e){ System.out.println(e.getMessage()); } catch (Exception e){ System.out.println(e.getMessage()); } }
——自定义异常类
throw还可以抛出自定义异常类。
自定义异常类的声明需要继承于现有的异常体系。
class MyException extends RuntimeException{ static final long serialVersionUID = -703489719076939L; //可以认为是一种标识 public MyException(){} public MyException(String message){ super(message); } }
此时我们可以抛出自定义的异常
class ThrowTest{ private int Number; public void judge(int num) throws MyException{ if(num>=0){ this.Number = num; } else{ throw new MyException("不能输入负数"); } } }
调用者修改
@Test public void test2(){ ThrowTest throwTest = new ThrowTest(); try{ throwTest.judge(-100); } catch (MyException e){ System.out.println(e.getMessage()); } }
以上是Java關鍵字throw、throws、Throwable怎麼用的詳細內容。更多資訊請關注PHP中文網其他相關文章!