文档

Java™教程
隐藏目录
集合接口
路径:集合类
课程:接口

集合接口

Collection(集合)代表一组对象,这些对象称为其元素。 Collection 接口用于传递希望具有最大普遍性的对象集合。 例如,按照约定,所有通用的集合实现都有一个以 Collection 为参数的构造函数。 这个构造函数被称为转换构造函数,它将新的集合初始化为包含指定集合中的所有元素,无论给定集合的子接口或实现类型是什么。 换句话说,它允许您转换集合的类型。

例如,假设您有一个 Collection<String> c,它可以是 ListSet 或其他类型的 Collection。 这个习惯用法创建一个新的 ArrayListList 接口的实现),最初包含 c 中的所有元素。

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

Collection 接口包含执行基本操作的方法,例如 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 及更高版本的 Collection 接口还公开了方法 Stream<E> stream()Stream<E> parallelStream(),用于从底层集合获取顺序或并行流(有关使用流的更多信息,请参见题为 Aggregate Operations 的教程)。

Collection 接口的功能与其表示一组对象的特性相符。它具有告诉您集合中有多少元素的方法(sizeisEmpty)、检查给定对象是否在集合中的方法(contains)、向集合中添加和删除元素的方法(addremove)以及提供集合上的迭代器的方法(iterator)。

addCollectionCollectiontrueremoveCollectiontrueCollection

遍历集合

有三种遍历集合的方法:(1) 使用聚合操作 (2) 使用for-each语法 和 (3) 使用Iterator迭代器。

聚合操作

在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)));

这只是关于使用流和聚合操作可以做的一些例子。有关更多信息和示例,请参阅题为聚合操作的教程。

集合框架一直提供了一些所谓的“批量操作”作为其API的一部分。这些方法操作整个集合,如containsAlladdAllremoveAll等。不要将这些方法与JDK 8中引入的聚合操作混淆。新的聚合操作和现有的批量操作(containsAlladdAll等)之间的关键区别在于,旧版本的操作都是可变的,意味着它们都会修改底层集合。相比之下,新的聚合操作不会修改底层集合。当使用新的聚合操作和lambda表达式时,您必须小心避免变异,以免在以后从并行流运行代码时引入问题。

for-each结构

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

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

迭代器

Iterator是一种对象,它使您能够遍历集合并选择性地从集合中删除元素(如果需要)。通过调用集合的iterator方法,可以获取集合的Iterator。以下是Iterator接口的定义。

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

hasNext方法在迭代中有更多的元素时返回truenext方法返回迭代中的下一个元素。remove方法从底层Collection中删除上一次由next返回的元素。每次调用next只能调用一次remove,如果违反此规则,将抛出异常。

请注意,在迭代进行时,Iterator.remove是唯一安全的修改集合的方式;如果在迭代进行时以任何其他方式修改底层集合,其行为是不确定的。

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

以下方法展示了如何使用Iterator来过滤任意Collection — 即遍历集合并删除特定元素。

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

这段简单的代码是多态的,这意味着它适用于任何Collection,而不管其具体实现方式。此示例演示了使用Java集合框架编写多态算法的简便性。

集合接口的批量操作

批量操作在整个Collection上执行操作。您可以使用基本操作来实现这些简便操作,但在大多数情况下,这样的实现效率较低。以下是批量操作:

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

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

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

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

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

此用法使用了Collections.singleton,它是一个静态工厂方法,返回一个只包含指定元素的不可变Set

Collection接口数组操作

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

例如,假设c是一个Collection。以下代码段将c的内容转储到一个新分配的Object数组中,其长度与c中的元素数量相同。

Object[] a = c.toArray();

假设c只包含字符串(可能是因为c的类型为Collection<String>)。以下代码段将c的内容转储到一个新分配的String数组中,其长度与c中的元素数量相同。

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

上一页: 接口
下一页: Set接口