リストまたはイテラブルは、 guavas を使用して簡単にフィルタリングできますfilter(Iterable<?> unfiltered, Class<T> type)
。この操作は 2 つのタスクを実行します。リストはフィルタリングされ、指定された型 T のシーケンスに変換されます。
ただし、最終的に特定の TIterables<Something<?>>
のサブシーケンスを取得したい場合がよくあります。Iterables<Something<T>>
Guava が型消去のためにそのままではこの問題を解決できないことは明らかです:Something<T>
はその T に関する直接的な情報を提供しません。
のようなものがあるとしましょうS<? extends Number>
。S<?>
キャストできるかどうかを示す述語を定義できればS<Double>
、それをファイラーとして使用できます。
<T extends Number> Predicate<S<?>> isOfType(Class<N> type) {...}
と:
Iterable<S<?>> numbers;
Iterable<S<?>> filtered = Iterable.filter(numbers, isOfType(Double.class));
これはフィルタリングのタスクを実行しますが、変換ステップを見逃しています。Predicate がうまく機能すると思う場合は、次のようにキャストすることを考えるかもしれません。
Iterable<S<Double>> doubles = (Iterable<S<Double>>) filtered;
しかし、これは醜いキャスト操作を暴露します。
Function<S<?>, S<Double>>
別の方法として、キャストを実行する を提供することもできます。ただし、要素をキャスト(または変換)できない場合は、Class.cast()
をスローするのではなくClassCastException
、単に返す必要があります。null
このようにして、明示的なキャストなしでシーケンスを変換できます。
<T extends Number> Function<S<?>, S<T>> castOrNull(Class<N> type) {...}
Iterable<S<Double>> doubles = Iterable.filter(numbers, castOrNull(Double.class));
ただし、リストは実際にはフィルタリングされていません。代わりに、に変換またはキャストできなかった各要素の null オブジェクトがまだ含まれていますS<Double>
。ただし、これは次のような追加のフィルタリング手順によって簡単に解決できます。
Iterable<S<Double>> doubles = Iterables.filter(doubles, Predicates.notNull());
2 番目の解決策は、私にははるかにスマートに思えます。定義されるはFunction
、キャスト (チェックされていない操作を隠す) を実行するか、必要に応じて新しいオブジェクトを実際に作成することができますS<T>
。
残りの質問は次のとおりです。必要な変換とフィルタリングを 1 つのステップで実行するよりスマートな方法はありますか? 次のようなユーティリティ関数を定義するだけです。
<I,O> Iterables<O> convert(
Iterables<O> input,
Function<? super I, ? extends O> convert,
Predicate<? super O> filter);
<I,O> Iterables<O> convert(
Iterables<O> input,
Function<? super I, ? extends O> convert);
Predicates.notNull()
2 番目の関数は、最初の関数を;でショートカットしたものです。
しかし、述語は不要なので、最初の関数も持つ価値がありPredicates.notNull()
ます。
を想像してみてくださいIterable<Iterable<? extends Number>>
。コンバーター関数Function<Iterable<? extends Number>, Iterable<Double>>
は、null を返す代わりに、空である可能性があるフィルター処理されたシーケンスを単に返す場合があります。追加のフィルターは、最終的に を使用して空のシーケンスを削除する場合がありますIterables.isEmpty()
。