是否有不允许空值的基本 Java Set 实现?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/591115/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 16:36:45  来源:igfitidea点击:

Is there a basic Java Set implementation that does not permit nulls?

javaapinullset

提问by Aaron K

The API for the Java Setinterface states:

Java Set接口的 API说明:

For example, some implementations prohibit nullelements and some have restrictions on the types of their elements

例如,有些实现禁止null元素,有些实现对其元素的类型有限制

I am looking for a basic Set implementation that does not require ordering (as ArrayListprovides for the Listinterface) and that does not permit null. TreeSet, HashSet, and LinkedHashSetall allow null elements. Additionally, TreeSet has the requirement that elements implement Comparable.

我正在寻找一个基本的 Set 实现,它不需要排序(因为ArrayListList接口提供)并且不允许null. TreeSetHashSetLinkedHashSet都允许空元素。此外, TreeSet 要求元素实现Comparable

It seems that no such basic Setexists currently. Does anyone know why? Or if one does exist where I can find it?

目前似乎没有这样的基本Set存在。有谁知道为什么?或者,如果确实存在我可以找到的地方?

[Edit]: I do not want to allow nulls, because later in the code my class will iterate over all elements in the collection and call a specific method. (I'm actually using HashSet<MyRandomObject>). I would rather fail fast than fail later or accidentally incur some bizarre behavior due to a nullbeing in the set.

[编辑]:我不想允许nulls,因为稍后在代码中,我的类将遍历集合中的所有元素并调用特定方法。(我实际上正在使用HashSet<MyRandomObject>)。我宁愿快速失败也不愿稍后失败,或者由于null在系列中而意外引发一些奇怪的行为。

采纳答案by Tom Hawtin - tackline

Better than extending a particular implementation, you can easily write a proxy implementation of Setthat checks for nulls. This analogous to Collections.checkedSet. Other than being applicable to any implementation, you can also be sure that you have overridden all applicable methods. Many flaws have been found by extending concrete collections which then have additional methods added in later versions.

比扩展特定实现更好,您可以轻松编写Set检查nulls的代理实现。这类似于Collections.checkedSet. 除了适用于任何实现之外,您还可以确保您已经覆盖了所有适用的方法。通过扩展具体集合发现了许多缺陷,然后在以后的版本中添加了额外的方法。

回答by mipadi

You could easily write your own, by subclassing an appropriate existing class, and overriding all relevant methods so that you can'tadd nullelements.

您可以轻松地编写自己的类,方法是将适当的现有类子类化,并覆盖所有相关方法,这样您就无法添加null元素。

回答by REA_ANDREW

I am not sure of a type which this is true. But could you not inherit from a collection or HashTable of your choice and override the Add method, throwing an exception if the element is null?

我不确定这是真的类型。但是您不能从您选择的集合或 HashTable 继承并覆盖 Add 方法,如果元素为 null 则抛出异常吗?

回答by Michael Myers

Why do you not want to allow null?

你为什么不想允许null

Do you want to throw an exception if nullis added to your set? If so, just do something like this:

如果null添加到您的集合中,您想抛出异常吗?如果是这样,只需执行以下操作:

private Set<Object> mySet = new HashSet<Object>() {
    @Override
    public boolean add(Object e) {
        if (e == null)
            throw new IllegalArgumentException("null"); // or NPE
        // or, of course, you could just return false
        return super.add(e);
    }
};

HashSet's addAll()calls add()repeatedly, so this is the only method you'd have to override.

HashSetaddAll()调用add()重复,所以这是您必须覆盖的唯一方法。

回答by cdmckay

I would say use composition instead of inheritance... it might be more work but it'll be more stable in the face of any changes that Sun might make to the Collections Framework.

我会说使用组合而不是继承......它可能需要更多的工作,但面对 Sun 可能对集合框架进行的任何更改,它会更加稳定。

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 ...
}

Note that this implementation does not depend on addAllcalling add(which is an implementation detail and should not be used because it cannot be guaranteed to remain true in all Java releases).

请注意,此实现不依赖于addAll调用add(这是一个实现细节,不应使用,因为不能保证在所有 Java 版本中都保持正确)。

回答by Julien Chastang

You may also wish to check out Google Collections. They are more null phobic, I believe.

您可能还希望查看Google Collections。我相信,他们更怕空。

回答by Uri

You could use apache collections and its PredicatedCollection class, and set the predicate to not allow nulls. You will get exceptions if someone sends nulls in.

您可以使用 apache 集合及其PredicatedCollection 类,并将谓词设置为不允许空值。如果有人发送空值,您将收到异常。

回答by TofuBeer

This is a failry general purpose way of doing it - you provide a Filter implementation that can restrict what gets added in whatevber way you want. Take a look at the source for java.util.Collections for ideas on the wrapping (I think my implementaiton of the FilteredCollection class is correct... but it is not extensivly tested). There is a sample program at the end that shows the usage.

这是一种失败的通用方法 - 您提供了一个过滤器实现,可以限制以您想要的任何方式添加的内容。查看 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);
    }
}

回答by Michael Borgwardt

BTW, if you'd asked for a Mapimplementation that does not allow nulls, the old java.util.Hashtabledoes not.

顺便说一句,如果你要求一个Map不允许空值的实现,旧的java.util.Hashtable则不允许。

回答by Pavithra

Hashtable does not allow null values......

Hashtable 不允许空值......