1

我正在寻找一种 Google Collections 方法,该方法返回不返回 null 的供应商序列的第一个结果。

我正在考虑使用 Iterables.find() 但在我的谓词中,我必须调用我的供应商以将结果与 null 进行比较,然后在 find 方法返回供应商后再次调用它。

4

3 回答 3

5

鉴于您对平静风暴的回答的评论(不想打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());

请注意,产生的 IterableIterables.transform()是惰性求值的,因此在对其进行Iterables.find()循环时,您只求值到第一个非null返回值,并且只求值一次。

于 2010-02-19T13:52:05.070 回答
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;如果调用 this 的代码需要检查是正常情况,则可能返回 null。

于 2010-02-19T17:18:32.013 回答
-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 是另一个类。

更新:在这种情况下 find 是错误的方法。你实际上需要一个这样的自定义函数,它可以返回两个值。如果您使用的是 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 的哈希图或长度为 2 的数组替换 DefaultMapEntry :)

于 2010-02-19T11:42:13.280 回答