Contents

Apache Commons Collections 库的SetUtils简介

1.概述

在本文中,我们将探索 Apache Commons Collections 库的SetUtils API。简而言之,这些实用程序可用于对Java 中的Set数据结构执行某些操作。

2. 依赖安装

为了让我们在项目中使用SetUtils库,我们需要在项目的pom.xml文件中添加以下依赖项:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

或者,如果我们的项目是基于 Gradle 的,我们应该将依赖项添加到项目的build.gradle文件中。此外,我们需要将mavenCentral()添加到**build.gradle文件的存储库部分:

compile 'org.apache.commons:commons-collections4:4.1'

3. predicatedSet

SetUtils库的predicatedSet()方法允许定义要插入到集合中的所有元素应满足的条件。它接受一个源Set对象和一个谓词。

我们可以使用它来轻松验证Set的所有元素是否满足特定条件,这在开发第三方库/API 时会很方便。

如果任何元素的验证失败,将抛出IllegalArgumentException 。下面的代码段防止将不以 ‘L’ 开头的字符串添加到sourceSet或返回的validatingSet中:

Set<String> validatingSet
  = SetUtils.predicatedSet(sourceSet, s -> s.startsWith("L"));

该库还具有predicatedSortedSet()predicatedNavigableSet()分别用于处理SortedSetNavigableSet

4. 集合的并集、差集和交集

该库具有可以计算Set元素的并集、差集和交集的方法。

difference()方法接受两个Set对象并返回一个不可变的SetUtils 设置视图对象。返回的SetUtilsSetView包含在 set a但不在 set b中的元素:

Set<Integer> a = new HashSet<>(Arrays.asList(1, 2, 5));
Set<Integer> b = new HashSet<>(Arrays.asList(1, 2));
SetUtils.SetView<Integer> result = SetUtils.difference(a, b);
 
assertTrue(result.size() == 1 && result.contains(5));

请注意,尝试在返回的SetUtils 上执行写操作,如add()addAll()SetView将抛出UnsupportedOperationException

要修改返回的结果,我们需要调用返回的SetUtilstoSet()方法。SetView获取一个可写的Set对象:

Set<Integer> mutableSet = result.toSet();

SetUtils库的union方法完全符合它的意思——它返回集合ab的所有元素。union方法还返回一个不可变的SetUtil.SetView对象:

Set<Integer> expected = new HashSet<>(Arrays.asList(1, 2, 5));
SetUtils.SetView<Integer> union = SetUtils.union(a, b);
 
assertTrue(SetUtils.isEqualSet(expected, union));

注意assert 语句中**使用的isEqualSet()方法。**它是SetUtils库的一个方便的静态方法,可以有效地检查两个集合是否相等。

要获得集合的交集,即集合a和集合b中都存在的元素,我们将使用SetUtilsintersection()方法。此方法还返回一个SetUtil.SetView对象:

Set<Integer> expected = new HashSet<>(Arrays.asList(1, 2));
SetUtils.SetView<Integer> intersect = SetUtils.intersection(a, b);
 
assertTrue(SetUtils.isEqualSet(expected, intersect));

5. 转换集合元素

让我们看看另一个令人兴奋的方法——SetUtils.transformedSet()。此方法接受一个Set对象和一个Transformer接口。在源集合的支持下,它使用Transformer接口的*transform()*方法来转换集合的每个元素。

转换逻辑在Transformer接口的*transform()*方法中定义,该方法应用于添加到集合中的每个元素。下面的代码片段将添加到集合中的每个元素乘以 2:

Set<Integer> a = SetUtils.transformedSet(new HashSet<>(), e -> e * 2  );
a.add(2);
 
assertEquals(a.toArray()[0], 4);

*transformSet()*方法非常方便——它们甚至可以用来转换集合的元素——比如从字符串到整数。只要确保输出的类型是输入的子类型。

假设我们正在使用SortedSetNavigableSet而不是HashSet,我们可以分别使用transformedSortedSet()transformedNavigableSet()

请注意,将一个新的HashSet实例传递给transformSet()方法。在将现有的非空Set传递给方法的情况下,不会转换预先存在的元素。

如果我们想要转换预先存在的元素(以及之后添加的元素),我们需要使用org.apache.commons.collections4.set.TransformedSet的*transformSet()*方法:

Set<Integer> source = new HashSet<>(Arrays.asList(1));
Set<Integer> newSet = TransformedSet.transformedSet(source, e -> e * 2);
 
assertEquals(newSet.toArray()[0], 2);
assertEquals(source.toArray()[0], 2);

请注意,源集中的元素被转换,结果被复制到返回的newSet

6. 设置析取

SetUtils库提供了一个静态方法,可用于查找集合析取。集合 a 和集合 b的析取是集合a和集合b唯一的所有元素。

让我们看看如何使用SetUtils库的*disjunction()*方法:

Set<Integer> a = new HashSet<>(Arrays.asList(1, 2, 5));
Set<Integer> b = new HashSet<>(Arrays.asList(1, 2, 3));
SetUtils.SetView<Integer> result = SetUtils.disjunction(a, b);
 
assertTrue(
  result.toSet().contains(5) && result.toSet().contains(3));

7. SetUtils库中的其他方法

SetUtils库中还有其他方法可以轻松处理集合数据:

  • 我们可以使用synchronizedSet()synchronizedSortedSet()来获得一个线程安全的Set。但是,如文档中所述,我们必须手动同步返回集的迭代器以避免非确定性行为
  • 我们可以使用SetUtils.unmodifiableSet()来获取只读集。请注意,尝试将元素添加到返回的Set对象将引发UnsupportedOperationException
  • 还有一个*SetUtils.emptySet()*方法,它返回一个类型安全、不可变的空集
  • SetUtils.emptyIfNull()方法接受一个可为空的Set对象。如果提供的Set为空,则返回一个空的只读 Set;否则,它返回提供的Set
  • SetUtils.orderedSet()将返回一个Set对象,该对象维护添加元素的顺序
  • *SetUtils.hashCodeForSet()*可以为一个集合生成一个哈希码——这样两个相同元素的集合将具有相同的哈希码
  • SetUtils.newIdentityHashSet()将返回一个使用==而不是equals()方法来匹配元素的HashSet请在此处 阅读其注意事项