Java 集合源码分析(四)-Collection

151 阅读12分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战

源码


public interface Collection<E> extends Iterable<E> {
    // 查询操作

    /**
     * 返回这个集合中的元素的数量
     * 如果这个集合包含多于 Integer.MAX_VALUE 个元素,返回 Integer.MAX_VALUE
     *
     * @return 这个集合中的元素的数量
     */
    int size();

    /**
     * 如果这个集合没有包含任何元素,返回 true
     *
     * @return <tt>true</tt> 如果这个集合没有包含任何元素
     */
    boolean isEmpty();

    /**
     * 如果这个集合没有包含指定元素,返回 true
     * 更正确的说,只有当至少一个元素在这个集合中满足 (o==null && e==null && o.equals(e)) 条件才返回 true
     *
     * @param o 要查询在这个集合中是否存在该元素
     * @return <tt>true</tt> 如果这个集合包含指定的元素
     * @throws ClassCastException 如果指定的元素和这个集合的数据类型不相融
     * @throws NullPointerException 如果指定的元素是 null,并且这个集合不允许 null 值
     */
    boolean contains(Object o);

    /**
     * 返回这个集合中元素的迭代器
     * 元素的返回不保证顺序(除非这个集合是某个提供保证顺序的类的实例)
     * 
     * @return 这个集合中元素的迭代器
     */
    Iterator<E> iterator();

    /**
     * 返回包含这个集合中所有元素的数组
     * 如果这个集合对它的迭代器返回元素的顺序做了任何保证,这个方法必须以相同顺序返回元素
     * 
     * 返回的数组是安全的,因为这个集合不维护对它的应用(换句话说,这个方法必须分配一个新数组,即使这个集合基于数组支持)因此,调用者可以自由修改返回的数组
     *
     * 这个方法充当基于数组 API 和基于集合 API 的桥梁
     *
     * @return 包含这个集合中所有元素的数组
     */
    Object[] toArray();
    
    /**
     * 返回包含这个集合中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型
     * 如果集合适合指定的数组,则返回元素在其中
     * 否则,通过指定数组的运行时类型和这个集合的大小分配一个新数组
     *
     * 如果这个集合适合指定数组,并且有剩余空间(即,数组中的元素比这个集合中的元素多),数组中紧随集合结束的元素设置为 null
     * (只有当调用者知道这个集合灭有包含任何 null 元素,才有助于确定这个集合的长度)
     *
     * 如果这个集合对它的迭代器返回元素的顺序做了任何保证,这个方法必须以相同顺序返回元素
     *
     * 像 toArray() 方法,这个方法充当基于数组 API 和基于集合 API 的桥梁
     * 进一步的讲,这个方法允许精确控制输出数组的运行时类型,并且可能在某种情况下,用于节省分配成本
     *
     * 假设 x 是一个已知只包含字符串的集合
     * 下面的代码可以用来将集合转存到一个新分配的字符串数组中
     *
     * <pre>
     *     String[] y = x.toArray(new String[0]);
     * </pre>
     *
     * 注意 toArray(new Object[0]) 在功能上与 toArray() 是完全相同的
     *
     * @param <T> 包含集合的数组的运行时类型
     * @param a 如果数组足够大将此集合的元素存储到其中,否则,因为这个目的分配一个相同运行时类型的新数组
     * @return 包含这个集合中所有元素的数组
     * @throws ArrayStoreException 如果指定数组的运行时类型不是这个集合中所有元素的运行时类型的父类
     * @throws NullPointerException 如果指定的数组为 null
     */
    <T> T[] toArray(T[] a);

    // 修改操作

    /**
     * 确保这个集合包含指定的元素(可选操作)
     * 如果这个集合因为调用这个方法而更改了结果,则返回 true(如果这个集合不允许重复,并且已经包含了指定元素,则返回 false)
     *
     * 支持这个操作的集合可能会设置什么元素可以添加到这个集合
     * 特别是,有的集合会拒绝添加 null 元素,有的会对添加元素的类型做限制
     * 集合类应该在它们的文档清晰指明任何添加元素的限制
     *
     * 如果集合不是因为它已经包含这个元素而拒绝添加指定元素,它一定会抛出异常(而不是返回 false)
     * 这保证了集合在调用这个方法返回后始终包含指定元素
     *
     * @param e 要确保在该集合中存在的元素 
     * @return <tt>true</tt> 如果这个集合因为这个方法调用而改变了
     * @throws UnsupportedOperationException 如果这个集合不支持添加操作 
     * @throws ClassCastException 如果指定元素的类阻止它添加到这个集合
     * @throws NullPointerException 如果指定元素是 null,并且这个集合不允许 null 元素
     * @throws IllegalArgumentException 如果元素的某些属性阻止它添加到这个集合
     * @throws IllegalStateException 如果因为插入限制,此时不能添加元素
     */
    boolean add(E e);

    /**
     * 从这个集合移除单个指定元素的实例,如果它存在(可选操作)
     * 更正确的说,如果这个集合包含一个或多个类似 (o==null && e==null && o.equals(e)) 的元素,则移除元素 e
     * 如果这个集合包含指定的元素,返回 true(或者相当于,如果这个集合因为这个方法调用而改变)
     * 
     * @param o 如果存在,则从这个集合移除的元素
     * @return <tt>true</tt> 如果一个元素因为这个方法调用结果被移除
     * @throws ClassCastException 如果指定元素和和这个集合的类型不兼容
     * @throws NullPointerException 如果指定元素是 null 元素,并且这个集合不支持 null 元素
     * @throws UnsupportedOperationException 如果这个集合不支持 remove 操作
     */
    boolean remove(Object o);

    // 批量操作

    /**
     * 如果这个集合包含指定集合的所有元素,返回 true
     *
     * @param  c 要检查集合中是否包含此集合 
     * @return <tt>true</tt> 如果这个集合包含指定集合的所有元素
     * @throws ClassCastException 如果指定集合有一个或多个元素和这个集合数据类型不同
     * @throws NullPointerException 如果指定集合包含一个或者多个 null 元素,并且这个集合不允许 null 元素,或者指定集合为 null
     * @see    #contains(Object)
     */
    boolean containsAll(Collection<?> c);

    /**
     * 添加指定集合的所有元素到这个集合(可选操作)
     * 如果指定集合在操作的过程中修改,这个操作的行为不明(这意味着,如果指定集合是这个集合,并且这个集合是非空的,这个调用的行为是不明的)
     *
     * @param c 包含要添加到这个集合的元素的集合
     * @return <tt>true</tt> 如果这个集合因为调用这个方法改变了
     * @throws UnsupportedOperationException 如果这个集合不支持 addAll 操作
     * @throws ClassCastException 如果指定集合的元素的类阻止它添加到这个集合
     * @throws NullPointerException 如果指定集合包含一个 null 元素,并且这个集合不支持 null 元素,或者指定集合是 null
     * @throws IllegalArgumentException 如果指定集合的元素的某些属性阻止它添加到这个集合
     * @throws IllegalStateException 如果因为插入限制,此时不能添加所有元素
     * @see #add(Object)
     */
    boolean addAll(Collection<? extends E> c);
    
    /**
     * 移除所有这个集合包含在指定集合的所有元素(可选操作)
     * 这个方法调用返回后,这个集合将不包含与指定集合共有的元素
     *
     * @param c 包含从这个集合中要移除的元素的集合
     * @return <tt>true</tt> 如果这个集合因为调用这个方法变化
     * @throws UnsupportedOperationException 如果这个集合不支持 removeAll 方法
     * @throws ClassCastException 如果这个集合中的一个或多个元素与指定集合不兼容
     * @throws NullPointerException 如果这个集合包含一个或者多个 null 值,并且指定集合不支持 null 值,或者指定集合是 null
     * @see #remove(Object)
     * @see #contains(Object)
     */
    boolean removeAll(Collection<?> c);
    
    /**
     * 移除在这个集合中满足给定断言的所有元素
     * 迭代期间或者由于断言导致的错误或者抛出运行时异常转发给调用方
     *
     * 默认实现使用集合的迭代器遍历所有元素
     * 每一个满足条件的元素使用 Iterator#remove() 移除
     * 如果这个集合的迭代器不支持消除,会在第一个匹配元素抛出 UnsupportedOperationException
     *
     * @param filter 为移除的元素返回 true 的断言
     * @return {@code true} 如果有任何一个元素被移除
     * @throws NullPointerException 如果这个指定的过滤器是 null 
     * @throws UnsupportedOperationException 如果这个集合的元素不能被删除
     *         如果一个满足条件的元素不能被删除或者如果通常不支持删除,实现应该抛出异常
     * @since 1.8
     */
    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
    
    /**
     * 只保留在这个集合中包含在指定集合中的元素(可选操作)
     * 换句话说,从这个集合移除所有不包含在指定集合的元素
     *
     * @param c 包含要保留在这个集合中的元素的集合
     * @return <tt>true</tt> 如果这个集合因为调用这个方法而改变
     * @throws UnsupportedOperationException 如果这个集合不支持 retainAll 操作 
     * @throws ClassCastException 如果这个集合的一个或者多个元素的类型与指定集合不相容
     * @throws NullPointerException 如果这个集合包含一个或者多个 null 元素,并且这个集合不支持 null 元素,或者指定集合是 null
     * @see #remove(Object)
     * @see #contains(Object)
     */
    boolean retainAll(Collection<?> c);
    
    /**
     * 从这个集合中移除所有的元素
     * 这个方法返回后,集合将为空
     *
     * @throws UnsupportedOperationException 如果这个集合不支持清理操作
     */
    void clear();


    // 比较和散列
    
    /**
     * 将指定对象和这个集合比较判断是否相等
     * 当集合接口没有对 Object.equals 合同添加大致的规约,直接实现集合接口(换句话说,创建一个不是 List 或者 Set 的类)的程序员必须格外谨慎,如果它们选择重写 Object.equals
     * 没有必要这样做,最简单的做法是依赖对象的实现,但是实现可能希望实现一个 ”值比较“ 代替默认的 ”引用比较“(List 和 Set 接口授权这样的值比较)
     * 
     * Object.equals 方法的普遍规约说明相等必须是对称的(换句话说,a.equals(b) 当且仅当 b.equals(a))
     * List.equals 和 Set.equals 合约说明 list 仅仅与其他 list 相等,并且 set 与其他 set 相等
     * 因此,当一个既不实现 List 接口也不实现 Set 接口的集合类与任何 list 或者 set 进行比较时,定制的 equals 方法必须返回 false(按照相同的逻辑,不可能编写一个正确实现既有 Set 接口,又有 List 接口的类)
     *
     * @param o 要和这个集合进行相等性比较的元素
     * @return <tt>true</tt> 如果指定对象与这个集合相等
     *
     * @see Object#equals(Object)
     * @see Set#equals(Object)
     * @see List#equals(Object)
     */
    boolean equals(Object o);

    /**
     * 返回这个集合的哈希值
     * 当 Collection 接口没有给 Object.hashCode 方法添加大致的合约规定,程序员应该注意任何重写 Object.equals 的类应该同样重写 >Object.hashCode 方法,为了满足 Object.hashCode 方法的大致的合约
     * 特别是 c1.equals(c2) 意味着 c1.hashCode()==c2.hashCode()
     * 
     * @return 这个集合的哈希值
     *
     * @see Object#hashCode()
     * @see Object#equals(Object)
     */
    int hashCode();
    
    /**
     * 在这个集合的元素上创建一个分离器
     *
     * 实现应该记录分离器报告的特征值
     * 如果分离器报告 Spliterator#SIZED,并且这个集合没有包含任何元素,就不要求报告这种特征值
     *
     * 默认实现应该被可以返回更有效的分离器的子类重写
     * 为了保护 stream() 和 parallelStream() 方法期望的懒惰行为,分离器们应该有不可变或同时发生的特性,或者延迟加载
     * 
     * 如果这些都不实用,重写类应该描述分离器的绑定记录原则和结构干涉,并且应该重写 stream() 和 parallelStream() 方法,通过分离器的 Supplier 创建流
     * 比如:
     * <pre>{@code
     *     Stream<E> s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics)
     * }</pre>
     * 这些请求确保从 stream() 创建流,并且 parallelStream() 方法将反映终端流操作启动时收集的内容
     *
     * 默认实现从集合的迭代器创建一个延迟绑定分离器
     * 这个分离器继承了集合迭代器的快速失败属性
     * 创建的分离器报告
     *
     * 创建的分离器会额外报告
     * 
     * 如果分离器不覆盖元素,那么除大小和补贴的额外特征值的报告,对客户控制、专门研究或简化计算没有任何帮助
     * 然而,这确实允许空集合分享不可变和空的分离器实例(看 Spliterators#emptySpliterator()),并且使客户端可以确定这样的分离器不包含任何元素
     *
     * @return 这个集合中元素的拆分器
     * @since 1.8
     */
    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    
    /**
     * 从这个集合返回一个顺序流作为它的数据源
     *
     * 当 spliterator() 方法不能返回一个不可变,同时发生或者延迟绑定分离器时,应该重写这个方法(详细看 spliterator())
     *
     * 默认实现是从集合的分离器创建一个顺序流
     *
     * @return 这个集合中元素上的顺序流
     * @since 1.8
     */
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }

    /**
     * 从这个集合返回一个可能并行的流作为它的数据源 
     * 此方法允许返回顺序流
     * 
     * 当 spliterator() 方法不能返回一个不可变,同时发生或者延迟绑定分离器时,应该重写这个方法(详细看 spliterator())
     *
     * 默认实现是从集合的分离器创建一个并行流
     *
     * @return 在这个集合中元素上可能存在的并行流
     * @since 1.8
     */
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
}

总结

  • 所有带入参的方法,入参不能为 null