Подтвердить что ты не робот

Существует ли базовая реализация Java Set, которая не допускает null?

Интерфейс API для Java Set гласит:

Например, некоторые реализации запрещают элементы null, а некоторые имеют ограничения на типы своих элементов

Я ищу базовую реализацию набора, которая не требует упорядочения (как ArrayList предоставляет List), и это не позволяет null. TreeSet, HashSet и LinkedHashSet все разрешают нулевые элементы. Кроме того, TreeSet имеет требование, чтобы элементы реализовали Comparable.

Кажется, что в настоящее время такой базовый Set не существует. Кто-нибудь знает, почему? Или если он существует, где я могу его найти?

[Изменить]: я не хочу разрешать null s, потому что позже в коде мой класс будет перебирать все элементы в коллекции и вызывать определенный метод. (Я использую HashSet<MyRandomObject > ). Я бы скорее не быстро, чем потерпел неудачу позже или случайно подвергся некоторому причудливому поведению из-за null, находящегося в наборе.

4b9b3361

Ответ 1

Лучше, чем расширение конкретной реализации, вы можете легко написать прокси-реализацию Set, которая проверяет наличие null s. Это аналогично Collections.checkedSet. Кроме того, что вы применимы к любой реализации, вы также можете быть уверены, что вы переопределили все применимые методы. Многие недостатки были обнаружены путем расширения конкретных коллекций, которые затем добавили дополнительные методы в более поздние версии.

Ответ 2

Я бы сказал, использовать композицию вместо наследования... это может быть больше работы, но она будет более стабильной перед лицом любых изменений, которые 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 ...
}

Обратите внимание, что эта реализация не зависит от addAll вызывающей add (которая является подробностью реализации и не должна использоваться, поскольку не может быть гарантировано, что она останется верной во всех выпусках Java).

Ответ 3

Не существует базовой проприетарной реализации Set, которая игнорирует или ограничивает null! Существует EnumSet, но он предназначен для хранения типов enum.

Однако создания собственной реализации можно избежать, если вы используете коллекции Guava или Commons:

1. Guava Решение:

Set noNulls = Constraints.constrainedSet(new HashSet(), Constraints.notNull());

2. Общие коллекции:

Set noNulls = new HashSet();
CollectionUtils.addIgnoreNull(noNulls, object);

Ответ 4

Вы можете легко написать свой собственный, путем подкласса соответствующего существующего класса и переопределения всех соответствующих методов, чтобы вы не могли добавлять элементы null.

Ответ 5

Вы можете использовать коллекции apache и класс PredicatedCollection и установить предикат для недопущения нулей. Вы получите исключения, если кто-то отправит нули.

Ответ 6

Это универсальный способ устранения сбоев - вы предоставляете реализацию фильтра, которая может ограничить то, что добавляется в нужный вам способ. Взгляните на источник для 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);
    }
}

Ответ 7

Да - в документах для com.google.common.collect.ImmutableSet:

Высокопроизводительный неизменяемый набор с надежным, заданным пользователем порядком итерации. Не разрешает нулевые элементы.

Ответ 8

Вы также можете проверить Коллекции Google. Я считаю, что они более пустые фобии.

Ответ 9

Я не уверен, что это так. Но не могли бы вы наследовать из коллекции или HashTable по вашему выбору и переопределить метод Add, выбрасывая исключение, если элемент имеет значение null?

Ответ 10

Кстати, если вы попросили реализацию Map, которая не разрешает null, старый java.util.Hashtable не делает.

Ответ 11

В этом конкретном вопросе/примере наверняка, если у вас есть вызов HashSet<MyRandomObject> mySet mySet.remove(null), прежде чем начинать итерацию по всем упомянутым вами элементам?

Ответ 12

для меня, я не нашел его, поэтому я 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)
    }
};

Ответ 13

Почему вы не хотите разрешать null?

Вы хотите создать исключение, если 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 addAll() вызывает add() несколько раз, так что это единственный метод, который вам придется переопределить.

Ответ 14

Hashtable не допускает нулевые значения......