Collections的singleton,singletonList,singletonMap

2020-07-14 16:58:44 浏览数 (1)

Collections的singleton,singletonList,singletonMap

今天记录一下在IDEA的sonarLint插件代码分析提示需要优化的代码:

代码语言:javascript复制
//converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_JSON_UTF8));
converter.setSupportedMediaTypes(Collections.singletonList(new MediaType("application", "json", StandardCharsets.UTF_8)));

这里只需要创建一个元素的List的时候用Arrays.asList()的话那插件就会在代码下报黄线提示你这是代码坏味道,建议优化。后面我就发现了使用Collectionssingleton的一系列方法创建单个元素集合使用:

  • 创建一个元素的Set:Set<T> singleton(T o)
  • 创建一个元素的List:List<T> singletonList(T o)
  • 创建一个元素的Map:Map<K, V> singletonMap(K key, V value)

PS:创建出来的都是

singleton

源码片段:

代码语言:javascript复制
/**
     * Returns an immutable set containing only the specified object.
     * 返回仅包含指定对象的不可变集合。
     * The returned set is serializable.
     * 返回的集合是可序列化的。
     *
     * @param  <T> the class of the objects in the set
     * @param <T>集合中对象的类
     * @param o the sole object to be stored in the returned set.
     * @param o唯一要存储在返回集中的对象。
     * @return an immutable set containing only the specified object.
     * @返回一个仅包含指定对象的不可变集合。
     */
    public static <T> Set<T> singleton(T o) {
        return new SingletonSet<>(o);
    }

 /**
     * @serial include
     * @序列包括
     */
    private static class SingletonSet<E>
        extends AbstractSet<E>
        implements Serializable
    {
        private static final long serialVersionUID = 3193687207550431679L;

        private final E element;

        SingletonSet(E e) {element = e;}

        public Iterator<E> iterator() {
            return singletonIterator(element);
        }

        public int size() {return 1;}

        public boolean contains(Object o) {return eq(o, element);}

        // Override default methods for Collection
        //覆盖Collection的默认方法
        @Override
        public void forEach(Consumer<? super E> action) {
            action.accept(element);
        }
        @Override
        public Spliterator<E> spliterator() {
            return singletonSpliterator(element);
        }
        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            throw new UnsupportedOperationException();
        }
    }

源码注释可以看到Returns an immutable set containing only the specified object.(返回仅包含指定对象的不可变集合。),可以说明这个方法返回的Set集合是不可变的,要是对其进行任何更改操作将会导致报出throw new UnsupportedOperationException();错误。

singletonList

这是最简单并且推荐的方法,可以在其中「创建不可变List的单个元素」。用这个方法创建的列表也是「不可变」的,所以你确定在任何情况下列表中不会有更多的元素。

Collections.singletonList()返回的List的容量始终是为**1**,要是对其进行任何更改操作也将会导致报出UnsupportedOperationException错误

源码片段:

代码语言:javascript复制
/**
     * Returns an immutable list containing only the specified object.
     * 返回仅包含指定对象的不可变列表。
     * The returned list is serializable.
     * 返回的列表是可序列化的。
     *
     * @param  <T> the class of the objects in the list
     * @param <T>列表中对象的类
     * @param o the sole object to be stored in the returned list.
     * @param是要存储在返回列表中的唯一对象。
     * @return an immutable list containing only the specified object.
     * @返回一个仅包含指定对象的不可变列表。
     * @since 1.3
     * @从1.3开始
     */
    public static <T> List<T> singletonList(T o) {
        return new SingletonList<>(o);
    }

/**
     * @serial include
     * @序列包括
     */
    private static class SingletonList<E>
        extends AbstractList<E>
        implements RandomAccess, Serializable {

        private static final long serialVersionUID = 3093736618740652951L;

        private final E element;

        SingletonList(E obj)                {element = obj;}

        public Iterator<E> iterator() {
            return singletonIterator(element);
        }

        public int size()                   {return 1;}

        public boolean contains(Object obj) {return eq(obj, element);}

        public E get(int index) {
            if (index != 0)
              throw new IndexOutOfBoundsException("Index: " index ", Size: 1");
            return element;
        }

        // Override default methods for Collection
        //覆盖Collection的默认方法
        @Override
        public void forEach(Consumer<? super E> action) {
            action.accept(element);
        }
        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void sort(Comparator<? super E> c) {
        }
        @Override
        public Spliterator<E> spliterator() {
            return singletonSpliterator(element);
        }
    }

PS:Array.asList()此方法也是快速创建List,创建出来的列表是「可变」的。

singletonMap

代码语言:javascript复制
Collections.singletonMap(key, value)

Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
map.put(key, value);

当你只有一个键/值对时,使用singletonMap更好,减少了不少代码。划重点:「只有一个键/值对时」

源码片段:

代码语言:javascript复制
/**
     * Returns an immutable map, mapping only the specified key to the
     * 返回一个不可变的映射,只将指定的键映射到
     * specified value.  The returned map is serializable.
     * 指定值返回的映射是可序列化的。
     *
     * @param <K> the class of the map keys
     * @param <K>映射键的类
     * @param <V> the class of the map values
     * @param <V>map值的类别
     * @param key the sole key to be stored in the returned map.
     * @param键是要存储在返回地图中的唯一键。
     * @param value the value to which the returned map maps <tt>key</tt>.
     * @param value是返回的地图将key映射到的值。
     * @return an immutable map containing only the specified key-value mapping.
     * 返回一个只包含指定键-值映射的不可变映射。
     * @since 1.3
     * @从1.3开始
     */
    public static <K,V> Map<K,V> singletonMap(K key, V value) {
        return new SingletonMap<>(key, value);
    }

/**
     * @serial include
     * @序列包括
     */
    private static class SingletonMap<K,V>
          extends AbstractMap<K,V>
          implements Serializable {
        private static final long serialVersionUID = -6979724477215052911L;

        private final K k;
        private final V v;

        SingletonMap(K key, V value) {
            k = key;
            v = value;
        }

        public int size()                                           {return 1;}
        public boolean isEmpty()                                {return false;}
        public boolean containsKey(Object key)             {return eq(key, k);}
        public boolean containsValue(Object value)       {return eq(value, v);}
        public V get(Object key)              {return (eq(key, k) ? v : null);}

        private transient Set<K> keySet;
        private transient Set<Map.Entry<K,V>> entrySet;
        private transient Collection<V> values;

        public Set<K> keySet() {
            if (keySet==null)
                keySet = singleton(k);
            return keySet;
        }

        public Set<Map.Entry<K,V>> entrySet() {
            if (entrySet==null)
                entrySet = Collections.<Map.Entry<K,V>>singleton(
                    new SimpleImmutableEntry<>(k, v));
            return entrySet;
        }

        public Collection<V> values() {
            if (values==null)
                values = singleton(v);
            return values;
        }

        // Override default methods in Map
        // 覆盖Map中的默认方法
        @Override
        public V getOrDefault(Object key, V defaultValue) {
            return eq(key, k) ? v : defaultValue;
        }

        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            action.accept(k, v);
        }

        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V putIfAbsent(K key, V value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean remove(Object key, Object value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V replace(K key, V value) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            throw new UnsupportedOperationException();
        }

        @Override
        public V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            throw new UnsupportedOperationException();
        }
    }

这三个内部类都是非常高效的

  • SingletonListSingletonSet 都用一个属性来表示拥有的元素,而不是用数组、列表来表示,SingletonMap 分别用两个属性表示 key/value,内存使用上更高效
  • 在方法的实现上也更高效,减少了循环。比如 size 方法都是直接返回 1 ,List.contains 方法是把参数与属性元素直接对比。

0 人点赞