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 weakHashSet = Collections.newSetFromMap(
    *              new WeakHashMap());
    *       
    *
    *Params:
    *map – the backing map
    *Type parameters:
    * – 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

你可能感兴趣的:(java,java,Collections,Set,Map,SetFromMap)