Java Set インターフェイスの状態のAPI:
たとえば、一部の実装では
null
要素が禁止されており、一部の実装では要素のタイプに制限があります。
順序付けを必要とせず( ArrayList が List インターフェイスを提供するため)、null
を許可しない基本的なSet実装を探しています。 TreeSet 、 HashSet 、および LinkedHashSet はすべてnull要素を許可します。さらに、TreeSetには、要素が実装するという要件があります Comparable 。
そのような基本的なSet
は現在存在しないようです。誰かが理由を知っていますか?または、私がそれを見つけることができる場所に存在する場合はどうなりますか?
[編集]:コードの後半でクラスがコレクション内のすべての要素を反復処理し、特定のメソッドを呼び出すため、null
sを許可したくありません。 (私は実際にHashSet<MyRandomObject
>を使用しています)。後で失敗したり、セットにnull
が含まれているために誤って奇妙な動作をしたりするよりも、早く失敗したほうがいいです。
特定の実装を拡張するよりも、Set
sをチェックするnull
のプロキシ実装を簡単に作成できます。これはCollections.checkedSet
に類似しています。すべての実装に適用可能である以外に、適用可能なすべてのメソッドをオーバーライドしたことを確認することもできます。具象コレクションを拡張することで多くの欠陥が発見され、その後のバージョンで追加のメソッドが追加されました。
継承の代わりにコンポジションを使用すると言います...それはより多くの作業になるかもしれませんが、SunがCollectionsFrameworkに加える可能性のある変更に直面してもより安定します。
public class NoNullSet<E> implements Set<E>
{
/** The set that is wrapped. */
final private Set<E> wrappedSet = new HashSet<E>();
public boolean add(E e)
{
if (e == null)
throw new IllegalArgumentException("You cannot add null to a NoNullSet");
return wrappedSet.add(e);
}
public boolean addAll(Collection<? extends E> c)
{
for (E e : c) add(e);
}
public void clear()
{ wrappedSet.clear(); }
public boolean contains(Object o)
{ return wrappedSet.contains(o); }
... wrap the rest of them ...
}
この実装は、addAll
がadd
を呼び出すことに依存しないことに注意してください(これは実装の詳細であり、すべてのJavaリリースでtrueを維持できるとは限らないため使用しないでください)。
Nullを無視または制約する基本的な独自のSet実装はありません! EnumSet がありますが、それは列挙型の包含に合わせたものです。
ただし、 Guava または Commons Collections のいずれかを使用すると、独自の実装を作成することを回避できます。
1。グアバソリューション:
Set noNulls = Constraints.constrainedSet(new HashSet(), Constraints.notNull());
2。 Commons Collections:
Set noNulls = new HashSet();
CollectionUtils.addIgnoreNull(noNulls, object);
これは、失敗した汎用的な方法です。必要な方法で追加されるものを制限できるFilter実装を提供します。ラッピングのアイデアについては、Java.util.Collectionsのソースを参照してください(FilteredCollectionクラスの実装は正しいと思います...しかし、拡張的にテストされていません)。最後に使用法を示すサンプルプログラムがあります。
public interface Filter<T>
{
boolean accept(T item);
}
import Java.io.Serializable;
import Java.util.Collection;
import Java.util.Iterator;
public class FilteredCollections
{
private FilteredCollections()
{
}
public static <T> Collection<T> filteredCollection(final Collection<T> c,
final Filter<T> filter)
{
return (new FilteredCollection<T>(c, filter));
}
private static class FilteredCollection<E>
implements Collection<E>,
Serializable
{
private final Collection<E> wrapped;
private final Filter<E> filter;
FilteredCollection(final Collection<E> collection, final Filter<E> f)
{
if(collection == null)
{
throw new IllegalArgumentException("collection cannot be null");
}
if(f == null)
{
throw new IllegalArgumentException("f cannot be null");
}
wrapped = collection;
filter = f;
}
public int size()
{
return (wrapped.size());
}
public boolean isEmpty()
{
return (wrapped.isEmpty());
}
public boolean contains(final Object o)
{
return (wrapped.contains(o));
}
public Iterator<E> iterator()
{
return new Iterator<E>()
{
final Iterator<? extends E> i = wrapped.iterator();
public boolean hasNext()
{
return (i.hasNext());
}
public E next()
{
return (i.next());
}
public void remove()
{
i.remove();
}
};
}
public Object[] toArray()
{
return (wrapped.toArray());
}
public <T> T[] toArray(final T[] a)
{
return (wrapped.toArray(a));
}
public boolean add(final E e)
{
final boolean ret;
if(filter.accept(e))
{
ret = wrapped.add(e);
}
else
{
// you could throw an exception instead if you want -
// IllegalArgumentException is what I would suggest
ret = false;
}
return (ret);
}
public boolean remove(final Object o)
{
return (wrapped.remove(o));
}
public boolean containsAll(final Collection<?> c)
{
return (wrapped.containsAll(c));
}
public boolean addAll(final Collection<? extends E> c)
{
final E[] a;
boolean result;
a = (E[])wrapped.toArray();
result = false;
for(final E e : a)
{
result |= wrapped.add(e);
}
return result;
}
public boolean removeAll(final Collection<?> c)
{
return (wrapped.removeAll(c));
}
public boolean retainAll(final Collection<?> c)
{
return (wrapped.retainAll(c));
}
public void clear()
{
wrapped.clear();
}
public String toString()
{
return (wrapped.toString());
}
}
}
import Java.util.ArrayList;
import Java.util.Collection;
public class Main
{
private static class NullFilter<T>
implements Filter<T>
{
public boolean accept(final T item)
{
return (item != null);
}
}
public static void main(final String[] argv)
{
final Collection<String> strings;
strings = FilteredCollections.filteredCollection(new ArrayList<String>(),
new NullFilter<String>());
strings.add("hello");
strings.add(null);
strings.add("world");
if(strings.size() != 2)
{
System.err.println("ERROR: strings.size() == " + strings.size());
}
System.out.println(strings);
}
}
適切な既存のクラスをサブクラス化し、関連するすべてのメソッドをオーバーライドして、できないnull
要素を追加することで、独自のクラスを簡単に作成できます。
Apacheコレクションとその PredicatedCollectionクラス を使用し、nullを許可しないように述語を設定できます。誰かがでnullを送信すると、例外が発生します。
はい -com.google.common.collect.ImmutableSet
のドキュメント内:
信頼性の高い、ユーザー指定の反復順序を備えた、高性能で不変のセット。 null要素を許可しません。
Googleコレクション もチェックしてみてください。彼らはもっと恐怖症ではないと私は信じています。
私にとっては見つからなかったので、overrode the add function
Collection<String> errors = new HashSet<String>() {
@Override
public boolean add(String s) {
return StringUtil.hasContent(s) && super.add(s);//we don't want add null and we allow HashSet.add(null)
}
};
これが本当のタイプはわかりません。しかし、選択したコレクションまたはHashTableから継承して、Addメソッドをオーバーライドし、要素がnullの場合に例外をスローすることはできませんか?
ところで、nullを許可しないMap
実装を要求した場合、古いJava.util.Hashtable
ではない。
この特定の質問/例では、あなたが言及したすべての要素に対して反復を開始する前に、_HashSet<MyRandomObject> mySet
_呼び出しmySet.remove(null)
がある場合は確かですか?