Collections.newSetFromMap

在看Netty源码时,遇到如下一段代码:

1
2
3
4

private final Set<ChannelHandlerContext> initMap = Collections.newSetFromMap(
        new ConcurrentHashMap<ChannelHandlerContext, Boolean>());

扒了一下该方法底层源码看了一下,如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
    return new SetFromMap<>(map);
}

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();
    }
}

可以看到SetFromMap的实现就仅仅只是对一个Map方法的包装。在netty的源码中主要用到了add方法和remove方法,且用法如下:

1
2
3
4
5
6
7

if (initMap.add(ctx)) {
    // do something
}

initMap.remove(ctx);

摘取SetFromMap的add方法和remove方法的实现如下:

1
2
3
4
5
6
7
8
9

public boolean add(E e) { 
    return m.put(e, Boolean.TRUE) == null; 
}

public boolean remove(Object o)   { 
    return m.remove(o) != null; 
}

remove很好理解,map中不存在这个元素,就返回false。对于add方法,我从来没有注意到set的add方法会在set中已经存在这个元素时返回false,这次又学习到了新的东西:

1
2
3
4
5

Set<String> set = new HashSet<>();
System.out.println(set.add("Hello")); // true
System.out.println(set.add("Hello")); // false