Collections.newSetFromMap使用场景

时间:2019-02-11
本文章向大家介绍Collections.newSetFromMap使用场景,主要包括Collections.newSetFromMap使用场景使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在看Spring源码的时候,偶然看到了BeanUtils.java类中有

private static final Set<Class<?>> unknownEditorTypes =
            Collections.newSetFromMap(new ConcurrentReferenceHashMap<>(64));

之前没看到过newSetFromMap这种用法,基本上都是直接new HashSet。
进入Collections类查看newSetFromMap方法的注释:


    /*
    *Returns a set backed by the specified map. The resulting set displays the same ordering, *concurrency, and performance characteristics as the backing map. In essence, this factory *method provides a Set implementation corresponding to any Map implementation. There is no *need to use this method on a Map implementation that already has a corresponding Set *implementation (such as HashMap or TreeMap).
    *Each method invocation on the set returned by this method results in exactly one method *invocation on the backing map or its keySet view, with one exception. The addAll method is *implemented as a sequence of put invocations on the backing map.
    *The specified map must be empty at the time this method is invoked, and should not be *accessed directly after this method returns. These conditions are ensured if the map is *created empty, passed directly to this method, and no reference to the map is retained, as *illustrated in the following code fragment:
    *          Set<Object> weakHashSet = Collections.newSetFromMap(
    *              new WeakHashMap<Object, Boolean>());
    *       
    *
    *Params:
    *map – the backing map
    *Type parameters:
    *<E> – the class of the map keys and of the objects in the returned set
    *Returns:
    *the set backed by the map
    *Throws:
    *IllegalArgumentException – if map is not empty
    *Since:
    *1.6
    */
    public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
        return new SetFromMap<>(map);
    }

    /**
     * @serial include
     */
    private static class SetFromMap<E> extends AbstractSet<E>
        implements Set<E>, Serializable
    {
        private final Map<E, Boolean> m;  // The backing map
        private transient Set<E> s;       // Its keySet

        SetFromMap(Map<E, Boolean> map) {
            if (!map.isEmpty())
                throw new IllegalArgumentException("Map is non-empty");
            m = map;
            s = map.keySet();
        }

        public void clear()               {        m.clear(); }
        public int size()                 { return m.size(); }
        public boolean isEmpty()          { return m.isEmpty(); }
        public boolean contains(Object o) { return m.containsKey(o); }
        public boolean remove(Object o)   { return m.remove(o) != null; }
        public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
        public Iterator<E> iterator()     { return s.iterator(); }
        public Object[] toArray()         { return s.toArray(); }
        public <T> T[] toArray(T[] a)     { return s.toArray(a); }
        public String toString()          { return s.toString(); }
        public int hashCode()             { return s.hashCode(); }
        public boolean equals(Object o)   { return o == this || s.equals(o); }
        public boolean containsAll(Collection<?> c) {return s.containsAll(c);}
        public boolean removeAll(Collection<?> c)   {return s.removeAll(c);}
        public boolean retainAll(Collection<?> c)   {return s.retainAll(c);}
        // addAll is the only inherited implementation

        // Override default methods in Collection
        @Override
        public void forEach(Consumer<? super E> action) {
            s.forEach(action);
        }
        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            return s.removeIf(filter);
        }

        @Override
        public Spliterator<E> spliterator() {return s.spliterator();}
        @Override
        public Stream<E> stream()           {return s.stream();}
        @Override
        public Stream<E> parallelStream()   {return s.parallelStream();}

        private static final long serialVersionUID = 2454657854757543876L;

        private void readObject(java.io.ObjectInputStream stream)
            throws IOException, ClassNotFoundException
        {
            stream.defaultReadObject();
            s = m.keySet();
        }
    }

可以看出来这个方法是从JDK1.6开始提供的,用于生成对Map进行包装的Set。这个Set和被包装的Map拥有相同的key顺序(遍历Set调用的还是Map的keySet),相同的并发特性(也就是说如果对ConcurrentHashMap进行包装,得到的Set也将线程安全)。本质上来说,这个工厂方法(newSetFromMap)就是提供了一个和Map实现相对应的Set实现。但并不是所有的Map实现类都需要用这个工厂方法转换成Set的,例如已经有了对应Set实现的HashMap(已经有了HashSet),TreeMap(TreeSet)

你可以用这个工厂包装WeakHashMap来生成一个Set(可以看作是WeakHashSet),因为并没有WeakHashSet这个现成的Set类可用。

参考文章:
1.http://www.jguru.com/faq/view.jsp?EID=1348143