成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

java異常的設(shè)計和使用

sshe / 2962人閱讀

摘要:異常處理作用調(diào)試程序定位缺陷。對異常的處理是系統(tǒng)容錯可靠性的一環(huán)。拋出需要具體子異常捕獲同時也需要具體子異常不同子異常處理會不同。如有基礎(chǔ)基類異常調(diào)用者可以選擇使用這個基類該類下面的所有子異常使用統(tǒng)一處理也可以多帶帶對子異常處理。

1 背景

1年前的文章,源于Sonar靜態(tài)代碼掃描中,項目歷史代碼里有兩個規(guī)則的ISSUE是異常相關(guān)的。

對于如何使用異常和設(shè)計異常,借助于業(yè)界的經(jīng)驗,拋磚引玉給大家分享下。盡量引用Java API和Spring的例子來說明。

2 為什么要有異常處理

正常運行情況下,程序順利運行下來不存在異常情況。但是往往程序正確運行依賴各種條件,既有代碼編寫邏輯正確,也有外部軟件、硬件運行正常。其中一項無法正常工作,程序就會發(fā)生異常。

因此,在程序語言層面,自然就會有異常處理?;虿东@錯誤故障,記錄并處理;或拋出錯誤故障 ,讓上一層調(diào)用方捕獲知道,并做下一步處理。

而Java語言程序語言層面,內(nèi)置支持異常處理。

3 異常處理作用

調(diào)試程序,定位缺陷。

異常是一種調(diào)試手段:什么出錯(異常類型),在哪出錯(異常堆棧),為什么錯(異常信息)

向前恢復(fù),繼續(xù)服務(wù)。

對異常的處理,是系統(tǒng)容錯、可靠性的一環(huán)。

4 如何使用異常 4.1 對公共接口的參數(shù)進行檢驗

通過當參數(shù)約定不符時,拋出unchecked異常,如ArrayList.get

/**
 * Returns the element at the specified position in this list.
 *
 * @param  index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}
 /**
 * Checks if the given index is in range.  If not, throws an appropriate
 * runtime exception.  This method does *not* check if the index is
 * negative: It is always used immediately prior to an array access,
 * which throws an ArrayIndexOutOfBoundsException if index is negative.
 */
private void rangeCheck(int index) {
    if (index >= size)
        // 拋出unchecked異常
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 
}

異常的信息必須清楚,包括但不限于引起異常的參數(shù)值。

/**
 * Constructs an IndexOutOfBoundsException detail message.
 * Of the many possible refactorings of the error handling code,
 * this "outlining" performs best with both server and client VMs.
 */
private String outOfBoundsMsg(int index) {
    return "Index: "+index+", Size: "+size;
}
4.2 不要嘗試處理代碼錯誤

對代碼錯誤,最好的策略是馬上失敗不要catch unchecked異常。
如NullPointerExceptionIndexOutOfBoundsException,
留下問題的審計日志,便于追蹤問題。

4.3 不要捕獲或拋出通用基礎(chǔ)異常
// Noncompliant
public void foo(String bar) throws Throwable {  
  throw new RuntimeException("My Message"); 
}
// Compliant
public void foo(String bar) {
  throw new MyOwnRuntimeException("My Message");
}
4.4 當轉(zhuǎn)換異常時使用異常鏈
try { 
  /* ... */ 
} catch (Exception e) { 
  // Noncompliant - exception is lost
  throw new RuntimeException("context"); 
}

上面的代碼就會把原始異常丟失,正確應(yīng)該保留原始異常。

try { 
  /* ... */ 
} catch (Exception e) { 
  throw new RuntimeException(e); 
}
4.5 記錄日志或拋出異常,但不要同時都做

對同一個代碼問題,多種的日志信息反而會讓開發(fā)人員難以簡單清晰定位問題。

try { 
  /* ... */ 
} catch (Exception e) { 
  LOGGER.error("系統(tǒng)執(zhí)行出錯",e); 
  throw new RuntimeException(e); 
}

雖然成熟的日志系統(tǒng)有調(diào)用鏈ID,方便我們把請求下面的日志全部拖出來。但上面的例子,最終系統(tǒng)日志會出現(xiàn)多個異常日志記錄,反而不及最終一個異常(帶異常鏈)唯一記錄到日志來得清晰。

4.6 不要在finally里拋出異常
try {
  //執(zhí)行時拋出異常e1 
  doSomethingThrowExceptionFirst(); 
} finally {
  //同時拋出異常e2
  doFinallyThrowExceptionSecond();
}

try{}異常e1,finally{}異常e2,當同時出現(xiàn)異常時,如果e2拋出e1丟失。
正常做法,doFinallyThrowExceptionSecond內(nèi)處理異?;蛘哂涗洰惓5饺罩?。

4.7 重用標準java異常

Java內(nèi)置異常在能明確表達當前代碼異常情況下可以拿來重用。

4.8 異常提供上下文

異常在java中是對象,保持和提供足夠信息 引起異常的參數(shù)值、錯誤細節(jié)描述、錯誤文本、關(guān)于改正的信息(當前重試的次數(shù))。
如org.springframework.core.convert.ConversionFailedException

/**
 * Create a new conversion exception.
 * @param sourceType the value"s original type
 * @param targetType the value"s target type
 * @param value the value we tried to convert
 * @param cause the cause of the conversion failure
 */
public ConversionFailedException(TypeDescriptor sourceType, TypeDescriptor targetType, Object value, Throwable cause) {
  super("Failed to convert from type " + sourceType + " to type " + targetType + " for value "" + ObjectUtils.nullSafeToString(value) + """cause);
  this.sourceType = sourceType;
  this.targetType = targetType;
  this.value = value;
}
4.9 盡可能地在接近問題產(chǎn)生處處理異常

往往對異常能做出正確決定的是直接調(diào)用者。
異常離源問題代碼越遠,越難跟蹤到源問題,也更難做有用的處理。
有時最好的異常處理是顯示被設(shè)計來控制流程的對象。

4.10 有效的記錄異常

對同一個異常只記錄一次,注意日志級別。

// 日志級別反例
String productsRequest = prepareProductsRequest(productId);
// 生產(chǎn)上日志級別一般為INFO,此處不會打印到日志文件
logger.debug (productsRequest);
try {
  String response = retrieveProducts(productsRequest);
  logger.debug (response);
} catch (NoSuchProductException e) {
  //當發(fā)生異常時,只記錄了異常,沒有productsRequest這個值
  logger.error(e);
}
//日志級別正例
String productsRequest = prepareProductsRequest(productId); 
try {
  String response = retrieveProducts(productsRequest); 
} catch (NoSuchProductException e) {
  //當發(fā)生異常時,把productsRequest也打印出來
  logger.error("request:" + productsRequest, e);
}
5 如何設(shè)計異常 5.1 異常命名明確

名字體現(xiàn)異常是什么。例如Java API中的FileNotFoundException,EOFException。拋出需要具體子異常,捕獲同時也需要具體子異常,不同子異常處理會不同。

5.2 異常定義歸類、有層次

按邏輯子模塊定義一個異?;蛘呦嚓P(guān)的一系列異常。
如org.springframework.core.NestedRuntimeException

有基礎(chǔ)基類異常,調(diào)用者可以選擇使用這個基類catch該類下面的所有子異常使用統(tǒng)一處理,也可以多帶帶對子異常處理。

//選擇使用這個基類catch該類下面的所有子異常使用統(tǒng)一處理
private Object getPropertyValue(Object obj) {
  try {
    this.beanWrapper.setWrappedInstance(obj);
    return this.beanWrapper.getPropertyValue(this.sortDefinition.getProperty()); 
  }catch (BeansException ex) { 
    //調(diào)用者可以選擇使用這個基類catch該類下面的所有子異常使用統(tǒng)一處理 
    logger.info("PropertyComparator could not access property - treating as null for sorting", ex); 
    return null;
  } 
}
//也可以多帶帶對子異常處理
} catch (IllegalStateException ex) {
  singletonObject = this.singletonObjects.get(beanName);
  if (singletonObject == null) {
  throw ex; }
} catch (BeanCreationException ex) { 
  //也可以多帶帶對子異常處理
  if (recordSuppressedExceptions) {
    for (Exception suppressedException : this.suppressedExceptions) {
      ex.addRelatedCause(suppressedException); 
    }
  }
  throw ex; 
}
5.3 異常的抽象層次和接口的抽象層次一致 5.3.1 為什么?

異常拋出聲明是接口定義的一部分 高級別的處理代碼catch低級別的異常,上下文缺少,不能很好的做出處理 如果不進行抽象,違反封裝原則(對外信息隱藏)減少系統(tǒng)可重用和清晰性。

//異常抽象層次和接口抽象層次一致
@Override
public Object getPropertyValue(String propertyName) throws BeansException {
  Field field = this.fieldMap.get(propertyName); 
  if (field == null) {
    //NotReadablePropertyException是InvalidPropertyException的子類 
    throw new NotReadablePropertyException(this.target.getClass(), propertyName, "Field "" + propertyName + "" does not exist"); 
  }
  try { 
    ReflectionUtils.makeAccessible(field); 
    return field.get(this.target);
  }
  catch (IllegalAccessException ex) {
    //封裝IllegalAccessException異常拋出和接口同一抽象層次的異常,InvalidPropertyException是BeansException的子類
    throw new InvalidPropertyException(this.target.getClass(), propertyName, "Field is not accessible", ex); 
  } 
}
5.3.2 在facade下的模塊化設(shè)計下,嚴格完整的定義異常。

大前提:是指如果一個子模塊以package形式組織,對外提供少量public的facade方法,內(nèi)部的異常設(shè)計。

異常嚴格完整設(shè)計(對于其他情況下的代碼也是需要的,5.2 異常定義歸類、有層次)

完整列出有可能異常、checked/unchecked異常;

如果異常能被組織成繼承結(jié)構(gòu),不僅是父類異常,所有異常都要定義。

讓異??杀磉_、保護封裝(前面已經(jīng)說明)

使用checked異常(注意前提說明,Spring里BeanException是unchecked異常,跟本身Bean在Spring中設(shè)計定位有關(guān))

5.4 什么時候使用檢測性異常和非檢測性異常(運行時異常) 5.4.1 當異常是可處理的,使用檢測性異常。

有可補償條件

調(diào)用方有協(xié)定可以處理

5.4.2 當異常是可處理的,使用運行時異常(非檢測性異常)

程序代碼錯誤

*接口定義被破壞,如參數(shù)是非法的,拋出IllegalArgumentException

5.5 錯誤類型編碼表述轉(zhuǎn)為異常表述

錯誤類型編碼能對錯誤進行分類定義,一般出現(xiàn)沒有內(nèi)置異常處理的編程語言,但有時第三方或者網(wǎng)絡(luò)協(xié)議都會有使用錯誤類型編碼這種方式。
Spring RestClientException的例子,HttpStatusCodeException下定義兩個子異常,分別是

HttpClientErrorException代表收到4xx

HttpServe rErrorException代表收到5xx

6 處理異常情況的策略

判斷請求不能正確執(zhí)行時,不執(zhí)行

請失敗時清理環(huán)境返回來異常,讓請求能根據(jù)異常選擇備選方案

守護掛起,直接條件允許正確執(zhí)行,嘗試完成請求

暫時的完成,請求完成,但不提交它直到可以完成。

恢復(fù),通過可接受的備選方案完成。備份資源須簡單便于使用。

上升到更高的處理。如請求人員來對系統(tǒng)進行操作處理

回滾,失敗時不產(chǎn)生影響

重試,通過重試在系統(tǒng)正常時完成請求。

參考資料
Exception Handling
知乎:如何優(yōu)雅的處理異常(java)?ylxfc等同學(xué)的回復(fù)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74116.html

相關(guān)文章

  • Java程序設(shè)計筆記

    摘要:對象的自動清除對象回收是由垃圾回收線程負責(zé)方法可以要求系統(tǒng)進行垃圾回收,僅僅是建議系統(tǒng)沒有析構(gòu)方法,但的有類似方法系統(tǒng)在回收時會自動調(diào)用對象的方法子類的方法可以在里面釋放系統(tǒng)資源,一般來說,子類的方法中應(yīng)該調(diào)用父類的方法。 對象的自動清除 對象回收是由垃圾回收線程負責(zé) System.gc()方法可以要求系統(tǒng)進行垃圾回收,僅僅是建議系統(tǒng) java沒有析構(gòu)方法,但Object的final...

    microcosm1994 評論0 收藏0
  • Effective Java 第三版 全文翻譯

    摘要:本章中的大部分內(nèi)容適用于構(gòu)造函數(shù)和方法。第項其他方法優(yōu)先于序列化第項謹慎地實現(xiàn)接口第項考慮使用自定義的序列化形式第項保護性地編寫方法第項對于實例控制,枚舉類型優(yōu)先于第項考慮用序列化代理代替序列化實例附錄與第版中項目的對應(yīng)關(guān)系參考文獻 effective-java-third-edition 介紹 Effective Java 第三版全文翻譯,純屬個人業(yè)余翻譯,不合理的地方,望指正,感激...

    galois 評論0 收藏0
  • Java經(jīng)典

    摘要:請注意,我們在聊聊單元測試遇到問題多思考多查閱多驗證,方能有所得,再勤快點樂于分享,才能寫出好文章。單元測試是指對軟件中的最小可測試單元進行檢查和驗證。 JAVA容器-自問自答學(xué)HashMap 這次我和大家一起學(xué)習(xí)HashMap,HashMap我們在工作中經(jīng)常會使用,而且面試中也很頻繁會問到,因為它里面蘊含著很多知識點,可以很好的考察個人基礎(chǔ)。但一個這么重要的東西,我為什么沒有在一開始...

    xcold 評論0 收藏0
  • Java設(shè)計模式之職責(zé)鏈模式

    摘要:簡介職責(zé)鏈模式有時候也叫責(zé)任鏈模式,它是一種對象行為的設(shè)計模式。中的就是使用了責(zé)任鏈模式。純的責(zé)任鏈模式的實際例子很難找到,一般看到的例子均是不純的責(zé)任鏈模式的實現(xiàn)。如果堅持責(zé)任鏈不純便不是責(zé)任鏈模式,那么責(zé)任鏈模式便不會有太大意義了。 Java設(shè)計模式之職責(zé)鏈模式 前幾天復(fù)習(xí)java的異常處理時,接觸到了責(zé)任鏈模式。在企業(yè)級應(yīng)用中,從前臺發(fā)過來的請求在后臺拋出異常,異常處理的設(shè)計一般...

    bergwhite 評論0 收藏0
  • Java異常處理

    摘要:可以被異常處理機制使用,是異常處理的核心。非檢測異常,在編譯時,不會提示和發(fā)現(xiàn)異常的存在,不強制要求程序員處理這樣的異常??傮w來說,語言的異常處理流程,從程序中獲取異常信息。處理運行時異常,采用邏輯合理規(guī)避同時輔助處理。 目錄 什么是Java異常? 當一個Exception在程序中發(fā)生的時候,JVM是怎么做的呢? 當我們編寫程序的時候如何對待可能出現(xiàn)的異常呢? 正文 1. 什么是J...

    Fourierr 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<