Google Collections供应商和查找

时间:2010-02-19 11:12:04

标签: java guava

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

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

3 个答案:

答案 0 :(得分:5)

鉴于你对Calm Storm答案的评论(不想两次致电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());

请注意,来自Iterables.transform()的Iterable是懒惰评估的,因此当Iterables.find()循环遍历它时,您只评估第一个非null - 返回一个,那只有一次。

答案 1 :(得分:3)

您询问了如何使用Google Collections执行此操作,但是如果不使用Google Collections,您就可以执行此操作。将它与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。

答案 2 :(得分:-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);
        }
    }
}

将DefaultMapEntry替换为大小为2的List或大小为1的hashmap或长度为2的数组:)