我正在寻找一种Google Collections方法,该方法返回一系列不返回null的供应商的第一个结果。
我正在考虑使用Iterables.find()但是在我的Predicate中我必须调用我的供应商将结果与null进行比较,然后在find方法返回供应商后再次调用它。
答案 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的数组:)