集合(有时称为容器)只是将多个元素分组到单个单元中的对象。集合用于存储、检索、操作和传达聚合数据。通常,它们表示形成自然组的数据项,例如扑克手(纸牌集合)、邮件文件夹(字母集合)或电话簿(名称到电话号码的映射)。如果您使用过 Java 编程语言(或者几乎任何其他编程语言),那么您已经熟悉集合。
集合框架是用于表示和操作集合的统一体系结构。所有集合框架都包含以下内容:
除了Java集合框架之外,最著名的集合框架示例是C++标准模板库(STL)和Smalltalk的集合层次结构。从历史上看,集合框架一直非常复杂,这使它们以具有陡峭的学习曲线而闻名。我们相信 Java 集合框架打破了这一传统,您将在本章中亲自学习。
Java 集合框架具有以下优点:
核心集合接口封装了不同类型的集合,如下图所示。这些接口允许独立于其表示形式的细节操作集合。核心集合接口是 Java 集合框架的基础。如下图所示,核心集合接口形成层次结构。
集合是一种特殊的集合,SortedSet是一种特别的集合,依此类推。还要注意,层次结构由两个不同的树组成——Map不是真正的Collection。
请注意,所有核心集合接口都是通用的。例如,这是Collection接口的声明。
public interface Collection...
语法告诉接口是通用的。当您声明集合实例时,您可以并且应该指定集合中包含的对象的类型。通过指定类型,编译器可以(在编译时)验证放入集合中的对象的类型是否正确,从而减少运行时的错误。
当您了解如何使用这些接口时,您将了解关于Java Collections Framework的大部分内容。本章讨论了有效使用接口的一般准则,包括何时使用哪个接口。您还将学习每个接口的编程习惯用法,以帮助您充分利用它。
为了保持核心集合接口的数量可管理,Java平台没有为每个集合类型的每个变体提供单独的接口。(这样的变体可能包括不可变、固定大小和仅追加。)相反,每个接口中的修改操作都被指定为可选的——给定的实现可能会选择不支持所有操作。如果调用了不支持的操作,则集合将抛出UnsupportedOperationException。实施负责记录他们支持的可选操作。Java平台的所有通用实现都支持所有可选操作。
以下列表介绍了核心集合接口:
最后两个核心集合接口只是Set和Map的排序版本:
集合表示一组称为其元素的对象。Collection接口用于传递需要最大通用性的对象集合。例如,按照惯例,所有通用集合实现都有一个接受collection参数的构造函数。此构造函数被称为转换构造函数,它初始化新集合以包含指定集合中的所有元素,无论给定集合的子接口或实现类型如何。换句话说,它允许您转换集合的类型。
例如,假设您有一个Collection<String>c,它可能是List、Set或其他类型的Collection。这个习惯用法创建了一个新的ArrayList(List接口的实现),最初包含c中的所有元素。
List 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(Collection<?>c))、boole retanall(Collection<>c)和void clear()。
数组操作的其他方法(如Object[] toArray()
and
)也存在。
在JDK8及更高版本中,Collection接口还公开了Stream<E>Stream()和 Stream
方法,用于从底层集合中获取顺序或并行流。(有关使用流的更多信息,请参阅题为“聚合操作”的课程。)
Collection接口实现了您所期望的功能,因为Collection表示一组对象。它有告诉您集合中有多少元素的方法(size,isEmpty),检查给定对象是否在集合中的方法(contains),向集合中添加和移除元素的方法,以及在集合上提供迭代器的方法(迭代器)。
add方法定义得足够一般,因此它对允许重复的集合和不允许重复的集都有意义。它保证在调用完成后Collection将包含指定的元素,如果Collection因调用而更改,则返回true。类似地,remove方法被设计为从Collection中删除指定元素的单个实例,假设它包含要开始的元素,并且如果Collection因此被修改,则返回true。
遍历集合有三种方法:(1)使用聚合运算(2)使用for每个构造;(3)使用Iterator。
在JDK8及更高版本中,迭代集合的首选方法是获得流并对其执行聚合操作。聚合操作通常与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)));
for each构造允许您使用for循环简明地遍历集合或数组。以下代码使用for each构造在单独的一行上打印出集合的每个元素:
for (Object o : collection)
System.out.println(o);
迭代器是一个对象,使您能够遍历集合,并根据需要选择性地从集合中删除元素。通过调用集合的迭代器方法,可以获得该集合的一个迭代器。以下是Iterator接口:
public interface Iterator {
boolean hasNext();
E next();
void remove(); //optional
}
如果迭代有更多的元素,那么hasNext方法返回true,next方法返回迭代中的下一个元素。remove方法从基础集合中移除next返回的最后一个元素。remove方法每次调用next只能调用一次,如果违反此规则,就会抛出异常。
请注意,Iterator.remove是在迭代过程中修改集合的唯一安全方法;如果在迭代过程中以任何其他方式修改了基础集合,则行为是未指定的。
当需要执行以下操作时,请使用迭代器而不是用于每个构造:
下面的方法向您展示了如何使用迭代器来筛选任意集合——也就是说,遍历集合以删除特定元素:
static void filter(Collection> c) {
for (Iterator> it = c.iterator(); it.hasNext(); )
if (!cond(it.next()))
it.remove();
}
这段简单的代码是多态的,这意味着无论实现如何,它都适用于任何Collection。这个例子展示了使用Java集合框架编写多态算法是多么容易。
批量操作对整个集合执行操作。您可以使用基本操作来实现这些简写操作,尽管在大多数情况下,这样的实现效率较低。以下是批量操作:
如果在执行操作的过程中修改了目标Collection,那么addAll、removeAll和retainAll方法都返回true。
作为批量操作能力的一个简单示例,请考虑以下习语,从Collection,c中删除指定元素e的所有实例。
c.removeAll(Collections.singleton(e));
更具体地说,假设您想从集合中删除所有null元素。
c.removeAll(Collections.singleton(null));
这个习惯用法使用Collections.singleton,这是一个静态工厂方法,返回一个只包含指定元素的不可变Set。
toArray方法是作为集合和旧API之间的桥梁提供的,旧API期望在输入时使用数组。数组操作允许将集合的内容转换为数组。不带参数的简单表单会创建一个新的Object数组。更复杂的形式允许调用方提供数组或选择输出数组的运行时类型。
例如,假设c是一个集合。下面的代码段将c的内容转储到新分配的Object数组中,该数组的长度与c中的元素数相同。
Object[] a = c.toArray();
假设已知c只包含字符串(可能是因为c的类型为Collection<String>)。下面的代码段将c的内容转储到新分配的String数组中,该数组的长度与c中的元素数量相同。
String[] a = c.toArray(new String[0]);
Java 集合全教程—Set 接口_Doker 多克的博客-CSDN博客
文章下方有交流学习区!一起学习进步!也可以前往官网,加入官方微信交流群
首发CSDN博客,创作不易,如果觉得文章不错,可以点赞收藏评论
你的支持和鼓励是我创作的动力❗❗❗