1. 概述

Eclipse Collections 是 Java 生态中一个强大的集合框架扩展库。简单来说,它不仅优化了标准集合的性能,还提供了许多 JDK 中没有的数据结构和实用功能。该框架同时支持可变(mutable)和不可变(immutable)两种集合实现,让开发者能根据场景灵活选择。

核心优势

  • 优化的集合实现
  • 丰富的数据结构扩展
  • 原生支持不可变集合
  • 完善的原始类型集合支持

2. Maven 依赖

pom.xml 中添加依赖即可开始使用:

<dependency>
    <groupId>org.eclipse.collections</groupId>
    <artifactId>eclipse-collections</artifactId>
    <version>8.2.0</version>
</dependency>

最新版本可在 Maven 中央仓库 查询。

3. 框架全景

3.1 基础集合类型

Eclipse Collections 提供的核心集合类型包括:

  • ListIterable - 有序集合,维护插入顺序且允许重复元素
    • 子接口:MutableListFixedSizeListImmutableList
    • 常用实现:FastListMutableList 的子类)
  • SetIterable - 无重复元素的集合
    • 子接口:SortedSetIterableUnsortedSetIterable
    • 常用实现:UnifiedSet(无序)
  • MapIterable - 键值对集合
    • 子接口:MutableMapFixedSizeMapImmutableMap
    • 常用实现:
      • UnifiedMap(无序)
      • MutableSortedMap(按自然顺序排序)
  • BiMap - 双向映射的键值对集合(继承 MapIterable
  • Bag - 允许重复的无序集合
    • 子接口:MutableBagFixedSizeBag
    • 常用实现:HashBag
  • StackIterable - 后进先出(LIFO)集合
    • 子接口:MutableStackImmutableStack
  • MultiMap - 允许一个键关联多个值的键值对集合

3.2 原始类型集合

框架提供了完整的原始类型集合支持,实现类名直接体现其存储类型。每种类型都提供可变、不可变、同步和不可修改四种形式:

  • 原始类型 Lists
  • 原始类型 Sets
  • 原始类型 Stacks
  • 原始类型 Bags
  • 原始类型 Maps
  • IntInterval(整数范围迭代器)

原始类型 Map 覆盖了所有键值组合场景(原始/对象键 × 原始/对象值)。特别说明:IntInterval 是一个可按步长迭代的整数范围。

4. 集合实例化

传统 Java 集合需要先创建空对象再逐个添加元素,而 Eclipse Collections 支持一行代码完成实例化和初始化:

MutableList<String> list = FastList.newListWith(
  "Porsche", "Volkswagen", "Toyota", "Mercedes", "Toyota");

类似地,创建 UnifiedSet

Set<String> comparison = UnifiedSet.newSetWith(
  "Porsche", "Volkswagen", "Toyota", "Mercedes");

创建 HashBag

MutableBag<String> bag = HashBag.newBagWith(
  "Porsche", "Volkswagen", "Toyota", "Porsche", "Mercedes");

Map 的创建需要传入 Pair 对象:

Pair<Integer, String> pair1 = Tuples.pair(1, "One");
Pair<Integer, String> pair2 = Tuples.pair(2, "Two");
Pair<Integer, String> pair3 = Tuples.pair(3, "Three");

UnifiedMap<Integer, String> map = new UnifiedMap<>(pair1, pair2, pair3);

当然也支持传统方式:

UnifiedMap<Integer, String> map = new UnifiedMap<>();

map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

⚠️ 关键区别

  • 不可变集合:没有 add()/remove() 等修改方法
  • 不可修改集合:调用修改方法会抛出 UnsupportedOperationException

5. 元素获取

获取 List 元素(与传统方式一致):

list.get(0);

获取 Map 值:

map.get(0);

便捷方法获取首尾元素:

map.getFirst(); // 获取首个元素
map.getLast();  // 获取末尾元素

基于自然顺序获取最大/最小值:

map.max(); // 最大值
map.min(); // 最小值

6. 集合遍历

Eclipse Collections 提供多种遍历方式,下面介绍常用操作。

6.1 集合过滤

select() 方法返回满足条件的元素子集(本质是过滤操作):

@Test
public void givenListwhenSelect_thenCorrect() {
    MutableList<Integer> greaterThanThirty = list
      .select(Predicates.greaterThan(30))
      .sortThis();
    
    Assertions.assertThat(greaterThanThirty)
      .containsExactly(31, 38, 41);
}

用 Lambda 简化:

return list.select(i -> i > 30)
  .sortThis();

reject()select() 的反向操作:

@Test
public void whenReject_thenCorrect() {
    MutableList<Integer> notGreaterThanThirty = list
      .reject(Predicates.greaterThan(30))
      .sortThis();
    
    Assertions.assertThat(notGreaterThanThirty)
      .containsExactlyElementsOf(this.expectedList);
}

6.2 collect() 方法

collect() 类似 Stream API 的 map() + collect(),对元素转换后收集到新集合:

@Test
public void whenCollect_thenCorrect() {
    Student student1 = new Student("John", "Hopkins");
    Student student2 = new Student("George", "Adams");
    
    MutableList<Student> students = FastList
      .newListWith(student1, student2);
    
    MutableList<String> lastNames = students
      .collect(Student::getLastName);
    
    Assertions.assertThat(lastNames)
      .containsExactly("Hopkins", "Adams");
}

当返回嵌套集合时,用 flatCollect() 扁平化处理:

@Test
public void whenFlatCollect_thenCorrect() {
    MutableList<String> addresses = students
      .flatCollect(Student::getAddresses);
    
    Assertions.assertThat(addresses)
      .containsExactlyElementsOf(this.expectedAddresses);
}

6.3 元素检测

detect() 返回第一个满足条件的元素:

@Test
public void whenDetect_thenCorrect() {
    Integer result = list.detect(Predicates.greaterThan(30));
    
    Assertions.assertThat(result)
      .isEqualTo(41);
}

anySatisfy() 检查是否存在满足条件的元素:

@Test
public void whenAnySatisfiesCondition_thenCorrect() {
    boolean result = list.anySatisfy(Predicates.greaterThan(30));
    
    assertTrue(result);
}

allSatisfy() 检查是否所有元素都满足条件:

@Test
public void whenAnySatisfiesCondition_thenCorrect() {
    boolean result = list.allSatisfy(Predicates.greaterThan(0));
    
    assertTrue(result);
}

6.4 partition() 方法

partition() 将集合按条件拆分为两个子集:

@Test
public void whenAnySatisfiesCondition_thenCorrect() {
    MutableList<Integer> numbers = list;
    PartitionMutableList<Integer> partitionedFolks = numbers
      .partition(i -> i > 30);
    
    MutableList<Integer> greaterThanThirty = partitionedFolks
      .getSelected()
      .sortThis();
    MutableList<Integer> smallerThanThirty = partitionedFolks
      .getRejected()
      .sortThis();
    
    Assertions.assertThat(smallerThanThirty)
      .containsExactly(1, 5, 8, 17, 23);
    Assertions.assertThat(greaterThanThirty)
      .containsExactly(31, 38, 41);
}

6.5 惰性迭代

惰性迭代延迟执行操作,直到结果被真正需要时才计算:

@Test
public void whenLazyIteration_thenCorrect() {
    Student student1 = new Student("John", "Hopkins");
    Student student2 = new Student("George", "Adams");
    Student student3 = new Student("Jennifer", "Rodriguez");

    MutableList<Student> students = Lists.mutable
      .with(student1, student2, student3);
    LazyIterable<Student> lazyStudents = students.asLazy();
    LazyIterable<String> lastNames = lazyStudents
      .collect(Student::getLastName);
    
    Assertions.assertThat(lastNames)
      .containsAll(Lists.mutable.with("Hopkins", "Adams", "Rodriguez"));
}

7. 元素配对

zip() 将两个集合元素配对(长度不一致时截断):

@Test
public void whenZip_thenCorrect() {
    MutableList<String> numbers = Lists.mutable
      .with("1", "2", "3", "Ignored");
    MutableList<String> cars = Lists.mutable
      .with("Porsche", "Volvo", "Toyota");
    MutableList<Pair<String, String>> pairs = numbers.zip(cars);
    
    Assertions.assertThat(pairs)
      .containsExactlyElementsOf(this.expectedPairs);
}

zipWithIndex() 将元素与索引配对:

@Test
public void whenZip_thenCorrect() {
    MutableList<String> cars = FastList
      .newListWith("Porsche", "Volvo", "Toyota");
    MutableList<Pair<String, Integer>> pairs = cars.zipWithIndex();
    
    Assertions.assertThat(pairs)
      .containsExactlyElementsOf(this.expectedPairs);
}

8. 集合转换

提供便捷方法转换集合类型:toList()toSet()toBag()toMap()

public static List convertToList() {
    UnifiedSet<String> cars = new UnifiedSet<>();
    
    cars.add("Toyota");
    cars.add("Mercedes");
    cars.add("Volkswagen");
    
    return cars.toList();
}

测试验证:

@Test
public void whenConvertContainerToAnother_thenCorrect() {
    MutableList<String> cars = (MutableList) ConvertContainerToAnother 
      .convertToList();
    
    Assertions.assertThat(cars)
      .containsExactlyElementsOf(
      FastList.newListWith("Volkswagen", "Toyota", "Mercedes"));
}

9. 总结

本文介绍了 Eclipse Collections 的核心特性和使用方法。这个框架通过优化实现和扩展功能,为 Java 开发者提供了更高效的集合操作方案。完整示例代码可在 GitHub 获取。

关键收获

  • 丰富的集合类型扩展
  • 原生支持不可变集合
  • 强大的原始类型集合
  • 简洁的 API 设计
  • 高效的惰性计算机制

原始标题:Introduction to Eclipse Collections

« 上一篇: NoException 介绍
» 下一篇: Java Weekly, 第190期