2010-02-19 86 views
1

我正在尋找Google Collections方法,該方法返回不返回null的供應商序列的第一個結果。Google Collections供應商和查找

我在尋找使用Iterables.find(),但是在我的Predicate中,我將不得不打電話給我的供應商,將結果與null進行比較,然後在find方法返回供應商後再次調用它。

回答

5

數組鑑於您的評論平息風暴的回答更換DefaultMapEntry(不要叫Supplier.get()的願望兩次) ,那麼怎麼樣:

private static final Function<Supplier<X>, X> SUPPLY = new Function<....>() { 
    public X apply(Supplier<X> in) { 
     // If you will never have a null Supplier, you can skip the test; 
     // otherwise, null Supplier will be treated same as one that returns null 
     // from get(), i.e. skipped 
     return (in == null) ? null : in.get(); 
    } 
} 

然後

Iterable<Supplier<X>> suppliers = ... wherever this comes from ... 

Iterable<X> supplied = Iterables.transform(suppliers, SUPPLY); 

X first = Iterables.find(supplied, Predicates.notNull()); 

注意,ITE來自Iterables.transform()的rable是懶惰評估的,因此當Iterables.find()在它上面循環時,你只評估到第一個非null - 返回一個,而且只有一次。

+1

+1用於回答所問的問題。不過,我認爲所問的問題應該是「這樣做的最佳方式是什麼」,而不是「使用谷歌收藏的方法是什麼」,所以我提供了另一個答案。 – 2010-02-19 17:23:48

+0

這確實對我有用。 – pledge 2010-02-19 19:18:05

+0

你應該接受這個答案。 – harschware 2010-02-22 19:21:55

-2

這是什麼問題?

List<Supplier> supplierList = //somehow get the list 
Supplier s = Iterables.find(supplierList, new Predicate<Supplier>(){ 
    boolean apply(Supplier supplier) { 
     return supplier.isSomeMethodCall() == null; 
    } 
    boolean equals(Object o) { 
     return false; 
    } 
}); 

你想保存一些行嗎?我可以考慮的唯一優化是靜態導入查找,以便您可以擺脫「Iterables」。另外,謂語是一個匿名內部類,如果你需要它在一個以上的地方,你可以創建一個類,它看上去就像這樣,

List<Supplier> supplierList = //somehow get the list 
Supplier s = find(supplierList, new SupplierPredicateFinder()); 

哪裏SupplierPredicateFinder是另一個類。

更新:在這種情況下查找是錯誤的方法。你實際上需要一個像這樣的自定義函數,它可以返回兩個值。如果您使用的是commons-collections,那麼您可以使用DefaultMapEntry,或者您可以簡單地返回Object [2]或Map.Entry。

public static DefaultMapEntry getSupplier(List<Supplier> list) { 
    for(Supplier s : list) { 
     Object heavyObject = s.invokeCostlyMethod(); 
     if(heavyObject != null) { 
      return new DefaultMapEntry(s, heavyObject); 
     } 
    } 
} 

大小爲2的列表或尺寸1的一個HashMap或長度2 :)

+0

在供應商(Google Collections)界面上有一個名爲get()的方法。這是一個耗時的計算。 Iterables.find在謂詞匹配時返回供應商,而不是get()的結果。所以在find()的結果之後,我需要再次調用get,這將需要再次執行計算。我可以使用MemoizingSupplier,但如果find方法返回供應商的結果而不是供應商自己,結果會更好。 – pledge 2010-02-19 11:54:17

+0

用更多代碼示例更新了答案! – 2010-02-19 13:57:05

+0

這個答案是不連貫的。根據原問題的內容,上半場無效。在下半年,當用戶只需要重對象時,爲什麼要返回供應商和重對象?我很困擾我們會很快向任何人推薦Map.Entry/Object [2]黑客(而且這是一種怪誕的黑客攻擊),除非真的需要。 – 2010-02-19 17:10:38

3

您問過如何使用Google收藏集來做到這一點,但您可以在不使用Google收藏集的情況下這樣做。將它與Cowan的答案(這是一個很好的答案)相比較 - 這更容易理解?

private static Thing findThing(List<Supplier<Thing>> thingSuppliers) { 
    for (Supplier<Thing> supplier : thingSuppliers) { 
    Thing thing = supplier.get(); 
    if (thing != null) { 
     return thing; 
    } 
    } 
    // throw exception or return null 
} 

在註釋中的 - 如果這是你的類的調用者的過錯,拋出IllegalArgumentException或IllegalStateException異常適當的;如果這不應該發生,請使用AssertionError;如果這是一個正常的事件,那麼調用它的代碼需要檢查,你可能會返回null。

+0

這是我原來的解決方案,我應該真的在問題中發佈它。然而,正如我們已經發現Predicates和Functions的一些很好的用法,我正在尋找是否存在像Suppliers.firstSupplied這樣的東西。正如Cowan的(工作)建議所顯示的,這可能是Java中的功能風格導致代碼難以理解的情況。測試通過這兩種解決方案。 – pledge 2010-02-19 19:29:18