0

次のコードを検討してください。

ICondition searchCondition, scopeCondition...
List<ICondition> filtered = CollectionUtil.filter(
    Arrays.asList(searchCondition, scopeCondition),
    CollectionUtil.isNonNull);

コンパイルに失敗します:

"filter(Collection<T>, CollectionUtil.Predicate<T>)型のメソッドCollectionUtilは引数に適用できません(List<ICondition>, CollectionUtil.Predicate<Object>)"

ICondition-固有の述語を定義すればすべて問題isNonNull()ありませんが、それはばかげており、何が問題なのか、それを修正する方法がわかりません。

ここに私のユーティリティ関数があります:

public interface Predicate<T> 
{
    boolean apply(T type); 
}

public static <T> List<T> filter(Collection<T> target, Predicate<T> predicate) 
{
    target = Collections.unmodifiableCollection(target);
    List<T> result = new ArrayList<T>();
    for (T element: target) {
        if (predicate.apply(element)) {
            result.add(element);
        }
    }
    return result;
}


// This predicate works as expected.
public static CollectionUtil.Predicate<String> isStringNonBlank = new CollectionUtil.Predicate<String>() {
    public boolean apply (String item) {
        return !StringUtils.isBlank(item);
    }
};

// This predicate looks fine, but fails in usage.
public static CollectionUtil.Predicate<Object> isNonNull = new CollectionUtil.Predicate<Object>() {
    public boolean apply (Object item) {
        return null != item;
    }
};

で 2 番目の述語を使用できないのはなぜfilter()ですか?

4

2 に答える 2

7

filter関数のpredicateパラメーターが適切に反変していないようです。次のように書き直してみてください。

public static <T> List<T> filter(Collection<? extends T> source,
                                 Predicate<? super T> predicate)
{
  final List<T> result = new ArrayList<T>(source.size());
  for (T element: source)
    if (predicate.apply(element))
      result.add(element);
  return result;
}

つまり、述語関数が typeより狭くない型を受け入れようとしている限り、 typeTのインスタンスT(または からさらに派生した型T) を使用して呼び出しても問題なく動作します。

于 2011-07-10T00:26:05.640 に答える
2

生成してみてくださいisNonNull:

private static class IsNonNullPredicate<T> implements Predicate<T> {
    public boolean apply(T item) {
        return null != item;
    }
}

これで、定数の代わりに util クラスのジェネリック メソッドを介してそれを返すことができます。

public <T> Predicate<T> isNonNull() {
    return new IsNonNullPredicate<T>();
}

または、毎回新しいインスタンスを作成する代わりに、保存されたインスタンスでチェックされていないキャストを実行します。

private final Predicate isNotNullPredicate = new IsNonNullPredicate();
public <T> Predicate<T> isNonNull() {
    return (Predicate<T>) isNotNullPredicate;
}

これはCollections、ユーティリティ メソッドでジェネリックをサポートするために、Java Collections ライブラリのクラスが行うことです。1.5 より前はCollections.EMPTY_LIST、ジェネリックが追加された後に を返すものがありましたList<Object>。ただし、それでは適切に生成されたリストが返されないため、呼び出しコンテキストに適合する任意の型のCollections.emptyList()を返すように追加されました。List

于 2011-07-10T00:20:56.627 に答える