Javaプログラムで、特定のプロパティに基づいてフィルタリングするBeanのリストがあります。
たとえば、JavaBeanのPersonのリストがあるとします。Personには、 'name'などの多くのプロパティがあります。
名前のリストもあります。
次に、名前リストに名前が含まれるすべての人を検索します。
Google Guavaを使用してこのフィルターを実行する最良の方法は何ですか?
これまでのところ、私はGuavaとApache beanutilsを組み合わせることを考えましたが、それはエレガントに思えません。
私はここにもリフレクション拡張ライブラリを見つけました: http://code.google.com/p/guava-reflection/ ですが、それを使用する方法がわかりません(ドキュメントはほとんどありません) 。
何かご意見は?
pS Pythonリスト内包表記が本当に欠けていると私に言うことができますか?
グアバなしで、昔ながらのやり方でやってください。 (Guava開発者として話す。)
List<Person> filtered = Lists.newArrayList();
for(Person p : allPersons) {
if(acceptedNames.contains(p.getName())) {
filtered.add(p);
}
}
Guavaでこれを行うことができますが、JavaはPythonではないため、Pythonに変換しようとすると、不便で読み取り不能なコードが永続するだけです。Guavaの関数型ユーティリティは控えめに使用し、コード行またはパフォーマンスに具体的で測定可能なメリットを提供する場合にのみ使用してください。
Iterable<Person> filtered = Iterables.filter(allPersons, new Predicate<Person>() {
@Override
public boolean apply(Person p) {
return acceptedNames.contains(p.getName());
}
});
名前のリストが大きい場合は、それをセット(HashSet、できれば)に変換し、リストではなく、このセットでcontainsを呼び出すほうがよいでしょう。containsはO(1) HashSetの場合、およびO(n) Listの場合。
文からの疑問を説明する:
これまでのところ、私はGuavaとApache beanutilsを組み合わせることを考えましたが、それはエレガントに思えません。
Javaは非常に人気があるにもかかわらず、 ファーストクラスの関数 サポートが不足しています*、 Java 8 で変更される可能性があるものは何ですか?
Iterable <Person> filtered = filter(allPersons, (Person p) -> acceptedNames.contains(p.getName()));
ラムダとそれはエレガントになります。
それまでは、次の中から選択できます。
Guava-wayは不変コレクション を作成することになるという@Loisの回答にも追加したいと思います(なぜなら、 それらは変更不可 、これはItem 15、Minimize mutability in Effective Javaでも説明されています(Joshua Bloch著)**:
ImmutableList.Builder<Person> builder = ImmutableList.builder();
for (final Person p : allPersons) {
if (acceptedNames.contains(p.getName())) {
builder.add(p);
}
}
ImmutableList<Person> filtered = builder.build();
(その実装の詳細はImmutableList.Builder
は、内部に一時的なArrayList
を作成します)。
*:それは私を大いに悩ませます、私はPython、JavaScriptおよびPerlの世界から来ました、 関数がよりよく扱われます
**:グアバとブロッホはさまざまな点で密結合です;)
LouisとJBの答えには十分に同意できません。私はグアバ反射を知りませんでした、多分 LambdaJ があなたが探しているものかもしれません:
// set up
Person me = new Person("Favio");
Person luca = new Person("Luca");
Person biagio = new Person("Biagio");
Person celestino = new Person("Celestino");
Collection<Person> meAndMyFriends = asList(me, luca, biagio, celestino);
// magic
Collection<Person> filtered = filter(having(on(Person.class).getName(),
isOneOf("Favio", "Luca")),
meAndMyFriends);
// test
assertThat(filtered, hasItems(me, luca));
assertEquals(2, filtered.size());
または、Scala、Clojure、またはGroovyが探しているものかもしれません...
Guava-reflectionの開発者と申しますと、このような早い段階でこのプロジェクトを放棄してしまったことを残念に思います(私には1日の仕事と妻と子供がいます:-))。私のビジョンは次のようなものでした:
Iterable<Object> thingsWithNames =
Iterables.filter(someData,
// this is a Predicate, obviously
BeanProperties.hasBeanProperty("name", String.class));
既存のコードはそこに約60%あるので、興味があれば私に連絡してください。おそらくこれを一緒に仕上げることができます。
Java8スタイルでは、ストリーム+フィルターを使用して目標を達成できます。
persons.stream()
.filter(p -> names.contains(p.getName()))
.collect(Collectors.toList());
Java8では、Collection.removeIf()を使用できます
List<Person> theList = ...;
theList.removeIf(
(Person p)->"paul".equals(p.getName())
);
もちろん、これにより現在のリストが変更されます。
リクエストされた一致を使用してリストをフィルタリングするために、guava、beanutilsを使用してジェネリックを使用する例を次に示します
/**
* Filter List
*
* @param inputList
* @param requestMatch
* @param invokeMethod
* @return
*/
public static <T> Iterable<T> predicateFilterList(List<T> inputList, final String requestMatch,
final String invokeMethod) {
Predicate<T> filtered = new Predicate<T>() {
@Override
public boolean apply(T input) {
boolean ok = false;
try {
ok = BeanUtils.getProperty(input, invokeMethod).equalsIgnoreCase(requestMatch);
}
catch (Exception e) {
e.printStackTrace();
}
return ok;
}
};
return Iterables.filter(inputList, filtered);
}
シングルスレッドアプリケーションでLinkedList
(またはremove操作がそれほど面倒ではないその他のコレクション)を使用する場合、最も効果的なソリューションは次のとおりです。
final Iterator<User> userIterator = users.iterator();
while (userIterator.hasNext()) {
if (/* your condition for exclusion */) {
userIterator.remove();
}
}