收集interface

Collection代表称为其元素的一组对象。 Collectioninterface用于传递需要最大通用性的对象集合。例如,按照惯例,所有通用集合实现都有一个带有Collection参数的构造函数。该构造函数称为转换构造函数,它初始化新集合以包含指定集合中的所有元素,无论给定集合的子interface或实现类型如何。换句话说,它允许您转换集合的类型。

例如,假设您有一个Collection<String> c,可以是ListSet或另一种Collection。这个惯用法创建了一个新的ArrayList(Listinterface的实现),最初包含c中的所有元素。

List<String> list = new ArrayList<String>(c);

或者-如果您使用的是 JDK 7 或更高版本,则可以使用菱形运算符:

List<String> list = new ArrayList<>(c);

Collectioninterface包含执行基本操作的方法,例如int size()boolean isEmpty()boolean contains(Object element)boolean add(E element)boolean remove(Object element)Iterator<E> iterator()

它还包含对整个集合(例如boolean containsAll(Collection<?> c)boolean addAll(Collection<? extends E> c)boolean removeAll(Collection<?> c)boolean retainAll(Collection<?> c)void clear())进行操作的方法。

还存在用于数组操作的其他方法(例如Object[] toArray()<T> T[] toArray(T[] a))。

在 JDK 8 和更高版本中,Collectioninterface还公开了Stream<E> stream()Stream<E> parallelStream()方法,用于从基础集合中获取 Sequences 或并行流。 (有关使用流的更多信息,请参见标题为Aggregate Operations的类。)

鉴于Collection代表一组对象,Collectioninterface可以实现您的期望。它具有告诉您集合中有多少个元素的方法(sizeisEmpty),检查给定对象是否在集合中的方法(contains),向集合中添加和删除元素的方法(addremove),以及在集合(iterator)上提供迭代器的方法。

add方法的定义已足够一般,因此它对于允许重复项和不允许重复项的集合有意义。它保证Collection在调用完成后将包含指定的元素,并且如果Collection由于调用而发生更改,则返回true。类似地,remove方法被设计为从Collection中删除指定元素的单个实例,假设该实例包含以其开头的元素,并且如果Collection作为结果被修改,则返回true

Traversing Collections

有三种遍历集合的方法:(1)使用聚合操作(2)带有for-each构造,以及(3)使用Iterator

Aggregate Operations

在 JDK 8 和更高版本中,对集合进行迭代的首选方法是获取流并对其执行聚合操作。聚合操作通常与 lambda 表达式结合使用,以使编程更富表现力,并且使用更少的代码行。以下代码依次遍历一组形状并打印出红色对象:

myShapesCollection.stream()
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));

同样,您可以轻松地请求并行流,如果集合足够大并且您的计算机具有足够的核心,这可能很有意义:

myShapesCollection.parallelStream()
.filter(e -> e.getColor() == Color.RED)
.forEach(e -> System.out.println(e.getName()));

使用此 API 收集数据的方式有很多种。例如,您可能想将Collection对象的元素转换为String对象,然后将它们连接起来,并用逗号分隔:

String joined = elements.stream()
    .map(Object::toString)
    .collect(Collectors.joining(", "));

或将所有员工的薪金相加:

int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));

这些只是您可以使用流和聚合操作执行的几个示例。有关更多信息和示例,请参见名为Aggregate Operations的类。

Collections 框架一直提供许多所谓的“批量操作”作为其 API 的一部分。这些方法包括对整个集合(例如containsAlladdAllremoveAll等)进行操作的方法。不要将这些方法与 JDK 8 中引入的聚合操作混淆。新的聚合操作与现有的批量操作之间的主要区别(containsAlladdAll等)是旧版本都是* mutative ,这意味着它们都修改了基础集合。相反,新的聚合操作不会*修改基础集合。使用新的聚合操作和 lambda 表达式时,必须注意避免突变,以免将来出现问题,如果以后从并行流中运行代码。

for-each Construct

for-each构造允许您使用for循环简洁地遍历集合或数组—参见for 语句。以下代码使用for-each构造在单独的一行上打印出集合的每个元素。

for (Object o : collection)
    System.out.println(o);

Iterators

Iterator是使您能够遍历集合并根据需要有选择地从集合中删除元素的对象。通过调用集合的iterator方法,您将获得一个Iterator。以下是Iteratorinterface。

public interface Iterator<E> {
    boolean hasNext();
    E next();
    void remove(); //optional
}

如果迭代具有更多元素,则hasNext方法返回true,而next方法返回迭代中的下一个元素。 remove方法从基础Collection中删除next返回的最后一个元素。每次调用next只能调用remove方法一次,如果违反了此规则,则抛出异常。

请注意,Iterator.remove是在迭代过程中修改集合的唯一安全方法。如果在进行迭代时以任何其他方式修改了基础集合,则行为未指定。

在需要执行以下操作时,请使用Iterator而不是for-each构造:

  • 删除当前元素。 for-each构造隐藏了迭代器,因此您无法调用remove。因此,for-each构造不可用于过滤。

  • 并行遍历多个集合。

下面的方法向您展示如何使用Iterator过滤任意Collection,即遍历集合以除去特定元素。

static void filter(Collection<?> c) {
    for (Iterator<?> it = c.iterator(); it.hasNext(); )
        if (!cond(it.next()))
            it.remove();
}

这个简单的代码是多态的,这意味着它适用于任何Collection,而与实现无关。此示例说明了使用 Java Collections Framework 编写多态算法有多么容易。

集合interface批量操作

批量操作对整个Collection执行操作。您可以使用基本操作来实现这些速记操作,尽管在大多数情况下,此类实现的效率较低。以下是批量操作:

  • containsAll —如果目标Collection包含指定Collection中的所有元素,则返回true

  • addAll —将指定Collection中的所有元素添加到目标Collection中。

  • removeAll —从目标Collection中删除其所有元素,这些元素也包含在指定的Collection中。

  • retainAll —从目标Collection中删除所有未包含在指定Collection中的元素。也就是说,它仅保留目标Collection中也包含在指定Collection中的那些元素。

  • clear-从Collection中删除所有元素。

如果在执行操作的过程中修改了目标Collection,则addAllremoveAllretainAll方法都返回true

作为批量操作功能的简单示例,请考虑以下惯用法以从Collectionc中删除指定元素e的所有实例。

c.removeAll(Collections.singleton(e));

更具体地说,假设您要从Collection中删除所有null元素。

c.removeAll(Collections.singleton(null));

这个习惯用法使用Collections.singleton,这是一种静态工厂方法,它返回仅包含指定元素的不可变Set

收集interface阵列操作

提供toArray方法作为集合与期望 Importing 数组的旧 API 之间的 bridge 梁。数组操作允许将Collection的内容转换为数组。没有参数的简单形式创建一个新的Object数组。更为复杂的形式允许调用方提供一个数组或选择输出数组的运行时类型。

例如,假设cCollection。以下代码段将c的内容转储到新分配的Object数组中,该数组的 Long 度与c中的元素数相同。

Object[] a = c.toArray();

假设已知c仅包含字符串(也许是因为c的类型为Collection<String>)。以下代码段将c的内容转储到新分配的String数组中,该数组的 Long 度与c中的元素数相同。

String[] a = c.toArray(new String[0]);