null を返さない一連の Suppliers の最初の結果を返す Google Collections メソッドを探しています。
Iterables.find() の使用を検討していましたが、Predicate ではサプライヤを呼び出して結果を null と比較し、find メソッドがサプライヤを返したら再度呼び出す必要があります。
Calm Storm の回答 ( Supplier.get()
2 回電話をかけたくないという希望) に対するコメントを考えると、次のようになります。
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
それは一度だけです。
Google Collections を使用してこれを行う方法を尋ねましたが、Google Collections を使用せずに行う方法を次に示します。それをコーワンの答えと比較してください(これは良い答えです)-どちらが理解しやすいですか?
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 を返す可能性があります。
これの何が問題なのですか?
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;
}
});
いくつかの行を保存しようとしていますか? 私が考えることができる唯一の最適化は、「イテラブル」を取り除くことができるように、検索結果を静的にインポートすることです。また、述語は匿名の内部クラスです。複数の場所で必要な場合は、クラスを作成でき、次のようになります。
List<Supplier> supplierList = //somehow get the list
Supplier s = find(supplierList, new SupplierPredicateFinder());
SupplierPredicateFinder は別のクラスです。
UPDATE : その場合、 find は間違った方法です。実際には、このような 2 つの値を返すことができるカスタム関数が必要です。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 のリストまたはサイズ 1 のハッシュマップまたは長さ 2 の配列に置き換えます:)