2016-08-19 16 views
8

我的問題是下面,我已經相當長的吸氣劑,即的try-catch而不是空的檢查使用幾個吸氣劑當

objectA.getObjectB().getObjectC().getObjectD().getObjectE().getName(); 

由於「壞」數據庫/實體設計(有些東西介紹晚於其他)發生getObjectB(),getObjectC()getObjectD()可能會返回NULL

通常我們用空檢查所有的時間,但在這種情況下,我不得不使用

ObjectB b = objectA.getObjectB(); 
if (b != null) { 
    ObjectC c = b.getObjectC(); 
    if (c != null) { 
     ObjectD d = c.getObjectD(); 
     if (d != null) 
      return d.getObjectE().getName(); 
    } 
} 
return ""; 

相反,它會更容易簡單地用一個try-catch塊

try { 
    return objectA.getObjectB().getObjectC().getObjectD().getObjectE().getName(); 
} catch (NullPointerException e) { 
    return ""; 
} 

在這種情況下,我真的不在乎哪個對象返回NULL,它顯示一個名稱或不顯示。使用try-catch而不是檢查是否有任何複雜性或設計不好?

感謝您的輸入。

+3

它通常是一個糟糕的設計,使用異常的完全正確的情況下,這是,如果吸氣返回'空'不是一個錯誤。 –

+0

多個if/else會增加圈複雜度!這是肯定的! –

+0

if(objectA.getObjectB()!= null && objectA.getObjectB()。getObjectC()!= null && ...)''?如果第一個錯誤,Java將不會進一步評估。 – Fildor

回答

7

如果是使用Java 8個選項,你可以使用Optional如下:

Optional.ofNullable(objectA) 
    .map(a -> a.getObjectB()) 
    .map(b -> b.getObjectC()) 
    .map(c -> c.getObjectD()) 
    .map(d -> d.getObjectE()) 
    .map(e -> e.getName()) 
    .orElse(""); 
+2

@ ST-DDT這很好,我用它在生產代碼中 - 可選的map()方法不會執行mapper函數,除非Optional包含一個值。 –

+0

哦,是的,你是對的。 –

+0

我把選項與Streams混淆了。 –

0

這真的只是你和你的團隊可以做出的判斷,但至少有一個客觀的事情我會說:如果其中一種方法返回null,你的第一個代碼塊將會更好地執行比你的第二個。相對於簡單的分支而言,拋出異常是很昂貴的。 (在沒有一個方法返回null的情況下,我認爲你避免分支第二可能是不可測量差不多快於第二)。在這兩種情況下,如果性能問題,在您的環境中進行測試。 (但是test it properly;微基準很難使用工具。)

大多數時候,當然在現實世界中差異並不重要,但這是運行時的顯着差異。

4

這種方法鏈接被稱爲「列車殘骸」,不是首選。 這樣的聲明也違反了Law of Demeter。讓我給你舉個例子,從書中清潔代碼通過羅伯特·Ç馬丁

String scratchDirPath = ctxt.getOptions().getScratchDir().getAbsolutePath(); 
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(scratchDirPath)); 
//write to file... 

這與你有什麼,這是一個不好的做法。這可能至少被重構爲如下:

Options options = ctxt.getOptions(); 
File scratchDir = options.getScratchDir(); 
String scratchDirPath = scratchDir.getAbsolutePath(); 
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(scratchDirPath)); 
//write to file... 

這仍然違反德米特法,但至少部分更好。 最好的方法是找出爲什麼需要scratchDirPath並要求ctxt對象提供給你。所以它看起來像 -

BufferedOutputStream bos = ctxt.createScratchDirFileStream(); 

這樣ctxt不公開所有的內部。這從ctxt的實現中分離出調用代碼。