只针对异常的情况才使用异常_如何以及何时使用异常
只針對異常的情況才使用異常
本文是我們名為“ 高級Java ”的學院課程的一部分。
本課程旨在幫助您最有效地使用Java。 它討論了高級主題,包括對象創(chuàng)建,并發(fā),序列化,反射等。 它將指導(dǎo)您完成Java掌握的旅程! 在這里查看 !
目錄
1.簡介 2.異常以及何時使用它們 3.已檢查和未檢查的異常 4.使用嘗試資源 5.異常和lambda 6.標準Java異常 7.定義自己的例外 8.記錄例外 9.異常和記錄 10.下一步是什么 11.下載源代碼1.簡介
Java中的異常是在程序流中發(fā)出異常(或異常)情況信號的重要工具,可能會阻止其進一步發(fā)展。 從本質(zhì)上講,那些特殊情況可能是致命的(程序無法再運行,應(yīng)該終止)或可恢復(fù)(程序可能會繼續(xù)運行,盡管某些功能可能不可用)。
在本教程的這一部分中,我們將逐步介紹在Java中使用異常的典型場景,討論已檢查和未檢查的異常,并探討一些極端情況和有用的習慣用法。
2.異常以及何時使用它們
簡而言之,異常是某種事件(或信號),它們在程序執(zhí)行期間發(fā)生并中斷常規(guī)執(zhí)行流程。 導(dǎo)致引入異常的想法是對過去使用的錯誤代碼和狀態(tài)檢查技術(shù)的替代。 從那時起,異常被廣泛接受為處理包括Java在內(nèi)的許多編程語言中的錯誤情況的標準方法。
只有一個與異常處理相關(guān)的重要規(guī)則(不僅在Java中):永遠不要忽略它們! 每個異常都應(yīng)至少記錄一次(請參閱Exceptions和logging ),但永遠不要忽略。 盡管如此,在某些罕見的情況下,可以安全地忽略異常,因為實際上可以做很多事情(請參閱示例中的使用try-with-resources部分)。
另外,在本教程的第6部分“ 如何有效地編寫方法”中 ,我們討論了參數(shù)驗證和健全性檢查。 異常是這些實踐的關(guān)鍵部分:每種公共方法都應(yīng)在進行任何實際工作之前驗證所有必需的前提條件,如果某些前提條件未得到滿足,則提出適當?shù)睦鈼l件。
3.已檢查和未檢查的異常
Java語言中的異常管理與其他編程語言不同。 這主要是因為Java中有兩類異常: 選中的異常和未選中的異常。 有趣的是,這兩個類在某種程度上是人為的,是由Java語言規(guī)則及其編譯器強加的(但是JVM對它們沒有影響)。
根據(jù)經(jīng)驗,未經(jīng)檢查的異常用于表示與程序邏輯和所做假設(shè)有關(guān)的錯誤條件(無效參數(shù),空指針,不支持的操作,等等)。 任何未經(jīng)檢查的異常都是RuntimeException的子類,這就是Java編譯器如何理解特定異常屬于未經(jīng)檢查的異常的類。
未經(jīng)檢查的異常不需要被調(diào)用方捕獲,也不需要作為方法簽名的一部分列出(使用throws關(guān)鍵字)。 NullPointerException是未經(jīng)檢查的異常的最著名的成員,這是Java標準庫中的聲明:
public class NullPointerException extends RuntimeException {public NullPointerException() {super();}public NullPointerException(String s) {super(s);} }因此,檢查的異常表示程序無法直接控制的區(qū)域(如內(nèi)存,網(wǎng)絡(luò),文件系統(tǒng)等)中的無效條件。 任何檢查到的異常都是Exception的子類。 與未檢查的異常相反,已檢查的異常必須被調(diào)用者捕獲,或者被列為方法簽名的一部分(使用throws關(guān)鍵字)。 IOException可能是檢查異常中最知名的一種:
public class IOException extends Exception {public IOException() {super();}public IOException(String message) {super(message);}public IOException(String message, Throwable cause) {super(message, cause);}public IOException(Throwable cause) {super(cause);} }在當時,將已檢查和未檢查的異常分開聽起來是個好主意,但是多年來,事實證明,它引入了更多樣板代碼,而不是解決實際問題的漂亮代碼模式。 Java生態(tài)系統(tǒng)中出現(xiàn)的典型(不幸的是非常麻煩)模式是將未檢查的異常隱藏(或包裝)在未檢查的異常中,例如:
try {// Some I/O operation here } catch( final IOException ex ) {throw new RuntimeException( "I/O operation failed", ex ); }這不是最好的選擇,但是如果精心設(shè)計自己的異常層次結(jié)構(gòu),可能會減少開發(fā)人員需要編寫的樣板代碼數(shù)量。
值得一提的是,Java中還有另一類異常擴展了Error類(例如, OutOfMemoryError或StackOverflowError )。 這些異常通常表示致命的執(zhí)行失敗,導(dǎo)致無法立即從此類錯誤情況中恢復(fù),從而導(dǎo)致程序立即終止。
4.使用嘗試資源
拋出的任何異常都會導(dǎo)致一些所謂的堆棧展開和程序執(zhí)行流程的更改。 結(jié)果是與未封閉的本機資源(例如文件句柄和網(wǎng)絡(luò)套接字)有關(guān)的可能的資源泄漏。 Java中行為良好的典型I / O操作(直到版本7)需要使用強制性的finally塊來執(zhí)行清理,并且通常看起來像這樣:
public void readFile( final File file ) {InputStream in = null;try {in = new FileInputStream( file );// Some implementation here} catch( IOException ex ) {// Some implementation here} finally {if( in != null ) {try {in.close();} catch( final IOException ex ) {/* do nothing */}}} }盡管如此, finally塊看起來確實很丑陋(不幸的是,此處無法做太多事情,因為在輸入流上調(diào)用close方法也可能導(dǎo)致IOException異常),無論嘗試關(guān)閉輸入流(并釋放背后的操作系統(tǒng)資源)發(fā)生了什么情況它)將被執(zhí)行。 在“ 異常以及何時使用它們 ”一節(jié)中,我們強調(diào)了一個事實,即永遠都不應(yīng)忽略異常,但是,用close方法拋出的異常可以說是從該規(guī)則中排除的一個例外。
幸運的是,自Java 7以來,該語言引入了一種名為try-with-resources的新結(jié)構(gòu),該結(jié)構(gòu)大大簡化了整體資源管理。 這是上面使用try-with-resources重寫的代碼片段:
public void readFile( final File file ) {try( InputStream in = new FileInputStream( file ) ) {// Some implementation here} catch( final IOException ex ) {// Some implementation here} }為了在try-with-resources塊中使用,資源唯一需要擁有的就是接口AutoCloseable 。 在后臺Java編譯器將此構(gòu)造擴展為更復(fù)雜的結(jié)構(gòu),但對開發(fā)人員而言,代碼看起來非常易讀和簡潔。 請在適當?shù)牡胤绞褂么朔浅7奖愕募夹g(shù)。
5.異常和lambda
在本教程的第3部分 , 如何設(shè)計類和接口中 ,我們已經(jīng)討論了Java 8的最新和最出色的功能,特別是lambda函數(shù)。 但是,我們尚未深入研究許多實際用例,并且例外是其中之一。
毫無疑問,未檢查的異常可以按預(yù)期工作,但是Java的lambda函數(shù)語法不允許指定可能拋出的已檢查的異常(除非這些異常由@FunctionalInterface本身定義)。 以下代碼段將不會以編譯錯誤“未處理的異常類型IOException”進行編譯(可能會在第03行引發(fā)):
public void readFile() {run( () -> {Files.readAllBytes( new File( "some.txt" ).toPath() );} );}public void run( final Runnable runnable ) {runnable.run();}現(xiàn)在唯一的解決方案是在lambda函數(shù)體內(nèi)捕獲IOException異常,然后重新拋出適當?shù)腞untimeException異常(不要忘記將原始異常作為原因傳遞),例如:
public void readFile() {run( () -> {try {Files.readAllBytes( new File( "some.txt" ).toPath() );} catch( final IOException ex ) {throw new RuntimeException( "Error reading file", ex );}} ); }聲明了許多功能接口,可以從其實現(xiàn)中引發(fā)任何異常,但是如果沒有(如Runnable),則將檢查的異常包裝(或捕獲)為非檢查的異常是唯一的方法。
6.標準Java異常
Java標準庫提供了大量有關(guān)異常的類,這些異常類被指定為覆蓋程序執(zhí)行期間發(fā)生的大多數(shù)通用錯誤。 下表列出了使用最廣泛的應(yīng)用程序,請在定義自己的應(yīng)用程序之前加以考慮。
| 例外類別 | 目的 |
| NullPointerException | 在需要對象的情況下嘗試使用null 。 |
| IllegalArgumentException | 方法已傳遞了非法或不適當?shù)膮?shù)。 |
| IllegalStateException | 方法已在非法或不適當?shù)臅r間被調(diào)用。 |
| IndexOutOfBoundsException | 某種索引(例如數(shù)組,字符串或向量)的索引超出范圍。 |
| UnsupportedOperationException | 不支持請求的操作。 |
| ArrayIndexOutOfBoundsException | 已使用非法索引訪問了數(shù)組。 |
| ClassCastException | 代碼已嘗試將對象強制轉(zhuǎn)換為不是實例的子類。 |
| EnumConstantNotPresentException | 試圖訪問一個enum的名稱和常量enum類型包含具有指定名稱的常量( enums一直在本教程中, 部分5 如何以及何時使用枚舉和注解 )。 |
| NumberFormatException | 嘗試將字符串轉(zhuǎn)換為數(shù)字類型之一,但是該字符串沒有適當?shù)母袷健? |
| StringIndexOutOfBoundsException | 索引為負或大于字符串的大小。 |
| IOException | 發(fā)生了某種I / O異常。 此類是由失敗或中斷的I / O操作產(chǎn)生的異常的一般類別。 |
表1 –標準Java異常
7.定義自己的例外
Java語言使定義自己的異常類非常容易。 精心設(shè)計的異常層次結(jié)構(gòu)允許實施詳細的細粒度錯誤條件管理和報告。 與往常一樣,找到合適的平衡非常重要:太多的異常類會使開發(fā)復(fù)雜化,并浪費大量的代碼來捕獲異常或?qū)⑵鋫鞑サ蕉褩V小?
強烈建議所有用戶定義的異常都應(yīng)繼承自RuntimeException類,并且應(yīng)屬于未經(jīng)檢查的異常類(但是,規(guī)則中始終存在排除項)。 例如,讓我們定義異常以進行身份??驗證撥號:
public class NotAuthenticatedException extends RuntimeException {private static final long serialVersionUID = 2079235381336055509L;public NotAuthenticatedException() {super();}public NotAuthenticatedException( final String message ) {super( message );}public NotAuthenticatedException( final String message, final Throwable cause ) {super( message, cause );} }此異常的目的是在信號插入過程中發(fā)出有關(guān)不存在或無效的用戶憑據(jù)的信號,例如:
public void signin( final String username, final String password ) {if( !exists( username, password ) ) {throw new NotAuthenticatedException("User / Password combination is not recognized" );} }將信息性消息與異常一起傳遞始終是一個好主意,因為它有助于對生產(chǎn)系統(tǒng)進行故障排除。 同樣,如果異常是由于另一個特殊情況導(dǎo)致的,則應(yīng)使用cause構(gòu)造函數(shù)參數(shù)保留初始異常。 這將有助于找出問題的真正根源。
8.記錄例外
在本教程的第6部分 , 如何有效地編寫方法中 ,我們介紹了Java方法的正確文檔。 在本節(jié)中,我們將花費更多時間討論如何使異常成為文檔的一部分。
如果方法作為其實現(xiàn)的一部分可能會引發(fā)檢查的異常,則它必須成為方法簽名的一部分(使用throws聲明)。 Java文檔工具分別具有@throws標記,用于描述這些異常。 例如:
/*** Reads file from the file system.* @throws IOException if an I/O error occurs.*/ public void readFile() throws IOException {// Some implementation here }相反,正如我們從Checked和unchecked異常一節(jié)中所知道的那樣,未經(jīng)檢查的異常通常不聲明為方法簽名的一部分。 但是,記錄它們?nèi)匀皇且粋€非常好的主意,因此方法的調(diào)用者將意識到可能引發(fā)的異常(使用相同的@throws標記)。 例如:
/*** Parses the string representation of some concept.* @param str String to parse* @throws IllegalArgumentException if the specified string cannot be parsed properly* @throws NullPointerException if the specified string is null*/ public void parse( final String str ) {// Some implementation here }請始終記錄您的方法可能引發(fā)的異常。 它將幫助其他開發(fā)人員從一開始就實施適當?shù)漠惓L幚砗突謴?fù)(后備)邏輯,從而避免他們對生產(chǎn)系統(tǒng)中的問題進行故障排除。
9.異常和記錄
日志記錄( http://en.wikipedia.org/wiki/Logfile )是或多或少復(fù)雜的Java應(yīng)用程序,庫或框架的重要組成部分。 它是應(yīng)用程序中發(fā)生的重要事件的日志,異常是此流程的關(guān)鍵部分。 在本教程的后面,我們可能會介紹Java標準庫提供的日志子系統(tǒng),但是請記住,以后應(yīng)該正確記錄和分析異常,以便發(fā)現(xiàn)應(yīng)用程序中的問題并解決關(guān)鍵問題。
10.下一步是什么
在本教程的這一部分中,我們介紹了異常,這是Java語言的一個非常重要的功能。 我們已經(jīng)看到異常是Java中錯誤管理的基礎(chǔ)。 異常使處理和發(fā)信號通知錯誤情況非常容易,并且與錯誤代碼,標志和狀態(tài)相反,一旦發(fā)生,則不能忽略異常。 在下一部分中,我們將討論一個非常熱門和復(fù)雜的主題:Java中的并發(fā)和多線程編程。
11.下載源代碼
這是關(guān)于如何以及何時使用異常的課程。 您可以在此處下載源代碼: advanced-java-part-8
翻譯自: https://www.javacodegeeks.com/2015/09/how-and-when-to-use-exceptions.html
只針對異常的情況才使用異常
總結(jié)
以上是生活随笔為你收集整理的只针对异常的情况才使用异常_如何以及何时使用异常的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js代码打包(js 发包 ddos)
- 下一篇: 绩效工作流_流绩效–您的想法