2013-07-25 64 views
1

是否有可能將下面的代碼包裝在可重用函數中?調用函數應該返回默認值,如果對象(或任何函數結果)爲空

編輯:這只是一個例子,我想對所有的遞歸深度

什麼,我想的是,下面的代碼生成一個有效的解決方案:

if (MyObject o == null || 
    o.getSubObject() == null || 
    o..getSubObject().getSubSubObject() == null /*|| 
    ... */) 
    return defaultValue; 
return o.getSubObject().getSubObject()/*...*/.getDesiredValue(); 

通過調用類似

Object defaultValue = null; 
Object result = NullSafeCall(o.getSubObject().getSubObject()/*...*/.getDesiredValue(), defaultValue); 

seond代碼塊只是一個想法,我不關心它是怎麼樣的,我想要的是,如果需要,我可以在調用更深的功能之前避免所有的檢查...

注射可以做到這一點,但是沒有其他更簡單的解決方案嗎?從來沒有看過注射前尚未...

EDIT2:例如,在另一種語言:http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator

+0

我對每個解決方案都感興趣......這個問題出現的原因是一個android項目,雖然... – prom85

回答

1

不是真的,你會寫這樣看起來可怕的和/或使用非常慢反射的任何代碼。除非您使用可以理解和更改您編寫的代碼的實際Java預處理器。

一個更好的(但與相當多的重構相關)的方法是確保有問題的值不可能爲null。例如,您可以修改單個訪問器(getSubObject()getDesiredValue()),使其永遠不會返回null:使它們返回默認值。訪問器默認值依次返回默認值。

+0

這是一個解決方案,我知道......其實,我不在乎這些函數是否返回null,所有我想要的是一個默認的(可能是空值)的結果,如果任何對象(無論哪個級別)爲空...以避免NullPointerException ...我只是覺得可能有一個,就像你說的,例如預處理器解決方案或其他...在我的情況下,我正在訪問一個抽象類的實例,它只能在特定點創建......在此之前,我不想創建沒有理由的空實例... – prom85

+0

類似這樣的:http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator不幸的是,這是一種不同的語言。 –

+0

順便說一句,發現了一個博客文章,提出了這個Java7 - 顯然它沒有得到。http://blog.joda.org/2009/01/java-7-null-default-and-null-safe_7527.html –

0

你可以做這樣的事情

public static Object NullSafeCall(MyObject o,Object defaultValue){ 
    if (o == null || o.getSubObject() == null) 
    { 
     return defaultValue; 
    } 
    else 
    { 
     return o.getSubObject().getDesiredValue(); 
    } 
} 

現在你可以調用這個方法如下

Object result = NullSafeCall(o, defaultValue); 
+0

謝謝,我知道這個特定的解決方案,我是什麼希望是一個函數/預編譯器或什麼語法與所有類和所有深度一起工作...所有對象的可重複使用的解決方案... – prom85

0

我建議只由

Object result = (o == null || o.subObject == null) ? defaultVlue : o.getSubObject().getDesiredValue(); 
更換

Object result = NullSafeCall(o.getSubObject().getDesiredValue(), defaultValue); 

僅當您可以重複使用時才創建方法......

+0

這只是一個特定的解決方案(作出一個單一的襯墊)...不可重用...我編輯我的主要帖子,使我更想明白我想要的 – prom85

0

您想要的是不可能的。必須理解的是,使用以下語法:Object result = NullSafeCall(o.getSubObject().getSubObject() ...);o.getSubObject().getSubObject()的部分將在之前評估任何控制傳遞給函數/方法,從而拋出異常。

在執行此類代碼之前,需要具有某種類型的上下文。我能想到的最接近此,可以使用像下面的例子匿名內部類來完成:

// intended to be implemented by an anonymous inner class 
interface NullSafeOperation<T> { 
    public T executeSafely(); 
}; 

// our executor that executes operations safely 
public static class NullSafeExecutor<T> { 
    public NullSafeExecutor() {} 

    public T execute(T defaultValue, NullSafeOperation<T> nso) { 
     T result = defaultValue; 
     try { 
      result = nso.executeSafely(); 
     } catch(NullPointerException e) { 
      // ignore 
     } 
     return result; 
    } 

    // utility method to create a new instance and execute in one step 
    public static <T> T executeOperation(T defaultValue, NullSafeOperation<T> nso) { 
     NullSafeExecutor<T> e = new NullSafeExecutor<T>(); 
     T result = e.execute(defaultValue, nso); 
     return result; 
    } 
} 


public static void main(String[] args) { 

    final String aNullString = null; 

    String result = NullSafeExecutor.executeOperation("MyDefault", new NullSafeOperation<String>() { 
     @Override 
     public String executeSafely() { 
      // trying to call a method on a null string 
      // it will throw NullPointerException but it will be catched by the executor 
      return aNullString.trim(); 
     } 
    }); 

    System.out.println("Output = " + result); // prints: Output = MyDefault 
} 
+0

我知道這個語法不能工作,它只顯示我想要的...你可以改變語法爲'NullSafeCall(「 o.getSubObject()。getDesiredValue()「,defaultValue);'...這很好...我可以解析字符串並解析子功能和檢查他們的所有返回值(反思)...我的問題中的代碼,如上所述,只是演示我想要的... – prom85

+0

我明白。我只想指出,如果沒有上下文,那麼這種方法是不可能的。上面的解決方案提供了一個:你的代碼被包裝在一個內部類中。如您所說的使用字符串版本和反射提供另一個上下文。 –

+0

你是對的......但是如果編譯器能夠解釋這樣的語法,那麼它將不需要上下文......而你的解決方案是一種解決方法,它可以工作,但它不能保證我編寫不必要的代碼這可能會自動生成...在這種情況下,圍繞最外層的函數調用嘗試/抓住會做的伎倆以及... – prom85

1

Java8有助於獲得你會得到與不俗的表現,我懷疑你的語法最接近;

// Evaluate with default 5 if anything returns null. 
int result = Optional.eval(5, o, x->x.getSubObject(), x->x.getDesiredValue()); 

這可以用這個工具類來完成;

class Optional { 
    public static <T, Tdef, T1> Tdef eval(Tdef def, T input, Function<T,T1> fn1, 
              Function<T1, Tdef> fn2) 
    { 
     if(input == null) return def; 
     T1 res1 = fn1.apply(input); 
     if(res1 == null) return def; 
     return fn2.apply(res1); 
    } 
} 

可悲的是,你需要一個單獨的eval()每鏈中的方法調用數來定義,所以你可能要定義幾個,但編譯時類型安全的和可重複使用與幾乎任何電話/類型。

+0

這聽起來很不錯,接近我想要的...可悲的是,只是Java 8 ...謝謝你的解決方案,但... – prom85