59

Google Collections ( update : Guava )を使用するときに、一部のコレクション処理コードを簡素化することについて質問があります。

「コンピューター」オブジェクトがたくさんあるので、それらの「リソース ID」のコレクションを作成したいと考えています。これは次のように行われます。

Collection<Computer> matchingComputers = findComputers();
Collection<String> resourceIds = 
    Lists.newArrayList(Iterables.transform(matchingComputers, new Function<Computer, String>() {
    public String apply(Computer from) {
        return from.getResourceId();
    }
}));

現在、getResourceId()null を返す可能性があります (現在、それを変更することはできません) が、この場合、結果の String コレクションから null を省略したいと考えています。

null を除外する 1 つの方法を次に示します。

Collections2.filter(resourceIds, new Predicate<String>() {
    @Override
    public boolean apply(String input) {
        return input != null;
    }
});

すべてを次のようにまとめることができます。

Collection<String> resourceIds = Collections2.filter(
Lists.newArrayList(Iterables.transform(matchingComputers, new Function<Computer, String>() {
    public String apply(Computer from) {
        return from.getResourceId();
    }
})), new Predicate<String>() {
    @Override
    public boolean apply(String input) {
        return input != null;
    }
});

しかし、このような単純なタスクの場合、これはエレガントではなく、読みやすさは言うまでもありません! 実際、単純な古い Java コード (派手な Predicate や Function をまったく使用していない) は、ほぼ間違いなく、はるかにクリーンになります。

Collection<String> resourceIds = Lists.newArrayList();
for (Computer computer : matchingComputers) {
    String resourceId = computer.getResourceId();
    if (resourceId != null) {
        resourceIds.add(resourceId);
    }
}

上記を使用することも確かにオプションですが、好奇心 (および Google Collections についてもっと学びたいという欲求) から、Google Collectionsを使用して、より短い方法またはよりエレガントな方法でまったく同じことを行うことができますか?

4

5 に答える 5

80

Predicatesここで役立つ述語がすでにあります -- Predicates.notNull()-- そしてIterables.filter()、これをもう少しクリーンアップするために使用Lists.newArrayList()できます。Iterable

Collection<String> resourceIds = Lists.newArrayList(
  Iterables.filter(
     Iterables.transform(matchingComputers, yourFunction),
     Predicates.notNull()
  )
);

が実際には必要なくCollection、 だけであるIterable場合は、Lists.newArrayList()呼び出しも不要になり、もう一度クリーンアップできます。

Functionが再び便利になり、次のように宣言されると最も役立つことがわかると思います

public class Computer {
    // ...
    public static Function<Computer, String> TO_ID = ...;
}

これにより、これがさらにクリーンアップされます (そして再利用が促進されます)。

于 2009-11-26T10:43:16.700 に答える
35

(Guava 12以降)を使用した少し「きれいな」構文FluentIterable

ImmutableList<String> resourceIds = FluentIterable.from(matchingComputers)
    .transform(getResourceId)
    .filter(Predicates.notNull())
    .toList();

static final Function<Computer, String> getResourceId =
    new Function<Computer, String>() {
        @Override
        public String apply(Computer computer) {
            return computer.getResourceId();
        }
    };

返されるリストはImmutableList. ただし、メソッドを使用copyInto()して要素を任意のコレクションに注ぐことができます。

于 2014-01-22T15:06:02.540 に答える
5

まず、どこかに定数フィルターを作成します。

public static final Predicate<Object> NULL_FILTER =  new Predicate<Object>() {
    @Override
    public boolean apply(Object input) {
            return input != null;
    }
}

次に、次を使用できます。

Iterable<String> ids = Iterables.transform(matchingComputers,
    new Function<Computer, String>() {
        public String apply(Computer from) {
             return from.getResourceId();
        }
    }));
Collection<String> resourceIds = Lists.newArrayList(
    Iterables.filter(ids, NULL_FILTER));

コード内のどこでも同じnullフィルターを使用できます。

他の場所で同じ計算関数を使用する場合は、それを定数にすることもできます。

Collection<String> resourceIds = Lists.newArrayList(
    Iterables.filter(
        Iterables.transform(matchingComputers, RESOURCE_ID_PROJECTION),
        NULL_FILTER));

確かに、C#に相当するものほど良くはありませんが、これはすべて、クロージャと拡張メソッドを使用してJava7ではるかに良くなるでしょう:)

于 2009-11-26T09:52:31.820 に答える
1

このように独自のメソッドを作成できます。これにより、apply メソッドから null を返す関数の null が除外されます。

   public static <F, T> Collection<T> transformAndFilterNulls(List<F> fromList, Function<? super F, ? extends T> function) {
        return Collections2.filter(Lists.transform(fromList, function), Predicates.<T>notNull());
    }

このメソッドは、次のコードで呼び出すことができます。

Collection c = transformAndFilterNulls(Lists.newArrayList("", "SD", "DDF"), new Function<String, Long>() {

    @Override
    public Long apply(String s) {
        return s.isEmpty() ? 20L : null;
    }
});
System.err.println(c);
于 2010-06-25T05:08:29.877 に答える