web-dev-qa-db-ja.com

nullを許可しない基本的なJava Set実装はありますか?

Java Set インターフェイスの状態のAPI:

たとえば、一部の実装ではnull要素が禁止されており、一部の実装では要素のタイプに制限があります。

順序付けを必要とせず( ArrayListList インターフェイスを提供するため)、nullを許可しない基本的なSet実装を探しています。 TreeSetHashSet 、および LinkedHashSet はすべてnull要素を許可します。さらに、TreeSetには、要素が実装するという要件があります Comparable

そのような基本的なSetは現在存在しないようです。誰かが理由を知っていますか?または、私がそれを見つけることができる場所に存在する場合はどうなりますか?

[編集]:コードの後半でクラスがコレクション内のすべての要素を反復処理し、特定のメソッドを呼び出すため、nullsを許可したくありません。 (私は実際にHashSet<MyRandomObject>を使用しています)。後で失敗したり、セットにnullが含まれているために誤って奇妙な動作をしたりするよりも、早く失敗したほうがいいです。

27
Aaron K

特定の実装を拡張するよりも、Setsをチェックするnullのプロキシ実装を簡単に作成できます。これはCollections.checkedSetに類似しています。すべての実装に適用可能である以外に、適用可能なすべてのメソッドをオーバーライドしたことを確認することもできます。具象コレクションを拡張することで多くの欠陥が発見され、その後のバージョンで追加のメソッドが追加されました。

27

継承の代わりにコンポジションを使用すると言います...それはより多くの作業になるかもしれませんが、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 ...
}

この実装は、addAlladdを呼び出すことに依存しないことに注意してください(これは実装の詳細であり、すべてのJavaリリースでtrueを維持できるとは限らないため使用しないでください)。

22
cdmckay

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);
7
Fritz Duchardt

これは、失敗した汎用的な方法です。必要な方法で追加されるものを制限できる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);
    }
}
2
TofuBeer

適切な既存のクラスをサブクラス化し、関連するすべてのメソッドをオーバーライドして、できないnull要素を追加することで、独自のクラスを簡単に作成できます。

2
mipadi

Apacheコレクションとその PredicatedCollectionクラス を使用し、nullを許可しないように述語を設定できます。誰かがでnullを送信すると、例外が発生します。

2
Uri

はい -com.google.common.collect.ImmutableSetのドキュメント内:

信頼性の高い、ユーザー指定の反復順序を備えた、高性能で不変のセット。 null要素を許可しません。

2
Matt Fenwick

Googleコレクション もチェックしてみてください。彼らはもっと恐怖症ではないと私は信じています。

1
Julien Chastang

私にとっては見つからなかったので、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)
    }
};
1

これが本当のタイプはわかりません。しかし、選択したコレクションまたはHashTableから継承して、Addメソッドをオーバーライドし、要素がnullの場合に例外をスローすることはできませんか?

0
REA_ANDREW

ところで、nullを許可しないMap実装を要求した場合、古いJava.util.Hashtable ではない。

0

この特定の質問/例では、あなたが言及したすべての要素に対して反復を開始する前に、_HashSet<MyRandomObject> mySet_呼び出しmySet.remove(null)がある場合は確かですか?

0
MichaelStoner