1. 概述

我们知道,在Java中,ArrayList可以包含重复值。

在这篇简短教程中,我们将探讨从ArrayList获取唯一值的几种方法。

2. 问题介绍

有时,我们需要从ArrayList中提取唯一值——例如,为了增强数据分析、提高效率或简化进一步处理。假设我们有一个包含操作系统名称的列表:

List<String> MY_LIST = Arrays.asList(new String[]{
  "Microsoft Windows",
  "Mac OS",
  "GNU Linux",
  "Free BSD",
  "GNU Linux",
  "Mac OS"});

在上面的代码中,我们已经从数组初始化了MY_LIST(/java-init-list-one-line#create-from-an-array)。目标是MY_LIST中获取唯一的操作系统名称列表

我们将讨论两种不同的解决方法。为了简化,我们将使用单元测试(/java-unit-testing-best-practices)和AssertJ断言来验证每种方法是否产生预期结果。

接下来,让我们看看如何操作。

3. 使用Set消除重复元素

SetList接口的一个重要区别是,Set不能容纳重复元素。因此,要获取MY_LIST的唯一元素,我们可以首先将MY_LIST转换为Set,**然后将Set转换回List**。

让我们创建一个测试来看看这如何工作:

List<String> result = new ArrayList<>(new HashSet<>(MY_LIST));
assertThat(result).containsExactlyInAnyOrder("Free BSD", "Microsoft Windows", "Mac OS", "GNU Linux");

细心的读者可能注意到我们使用了containsExactlyInAnyOrder()方法进行验证。这是因为我们将MY_LIST转换为了HashSet,而**HashSet不维护插入顺序**。

**如果需要保持插入顺序,我们可以将列表转换为LinkedHashSet**:

result = new ArrayList<>(new LinkedHashSet<>(MY_LIST));
assertThat(result).containsExactly("Microsoft Windows", "Mac OS", "GNU Linux", "Free BSD");

正如我们所见,这次我们使用了containsExactly()方法来验证结果。它不仅检查元素值,还检查它们的顺序。

4. 使用Stream API

Java 8引入的Stream API是其重要特性之一。它允许我们处理元素集合。

要从流中删除重复项,我们只需调用distinct()方法:

List<String> result = MY_LIST.stream()
  .distinct()
  .collect(toList());
assertThat(result).containsExactly("Microsoft Windows", "Mac OS", "GNU Linux", "Free BSD");

运行测试时,它会通过。

值得一提的是,Collectors.toList()始终保留流的原始顺序,除非我们将流转换为无序模式,例如通过调用unordered()或使用Collectors.toSet()将其转换为HashSet。因此,我们使用containsExactly()方法验证result列表。

5. 总结

在Java开发中,从列表中获取唯一值是一个常见需求。在这篇文章中,我们深入探讨了解决这个问题的两种方法:

  • List转换为Set,然后将Set再转换回List
  • 使用Stream API的distinct()功能

通过详尽的示例,我们展示了这些技术如何有效地从列表中提取唯一元素。此外,我们还讨论了如何保持结果列表中元素的顺序,使其与原始输入列表保持一致。

如往常一样,这里展示的所有代码片段都在GitHub上可用。