1. 概要

EclipseコレクションはJava用のもう1つの改良されたコレクションフレームワークです。

簡単に言えば、最適化された実装と、コアJavaにはない追加のデータ構造と機能を提供します。

ライブラリは、すべてのデータ構造の可変および不変の両方の実装を提供します。

2. Mavenの依存関係

次のMaven依存関係をpom.xmlに追加することから始めましょう。

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

ライブラリの最新バージョンは、 Maven CentralRepositoryにあります。

3. 大きな絵

3.1. 基本的なコレクションタイプ

Eclipseコレクションの基本的なコレクションタイプは次のとおりです。

  • ListIterable –挿入順序を維持し、要素の重複を許可する順序付けられたコレクション。 サブインターフェイスには、 MutableList FixedSizeList 、およびImmutableListが含まれます。 最も一般的なListIterableの実装は、MutableListのサブクラスであるFastListです。
  • SetIterable –重複する要素を許可しないコレクション。 ソートすることも、ソートしないこともできます。 サブインターフェイスには、SortedSetIterableおよびUnsortedSetIterableが含まれます。最も一般的なunsortedSetIterableの実装はUnifiedSet
  • MapIterable –キーと値のペアのコレクション。 サブインターフェイスには、 MutableMap FixedSizeMap 、およびImmutableMapが含まれます。 2つの一般的な実装は、UnifiedMapMutableSortedMapです。 UnifiedMap は順序を維持しませんが、MutableSortedMapは要素の自然な順序を維持します
  • BiMap –どちらの方向にも反復できるキー/値のペアのコレクション。 BiMapMapIterableインターフェースを拡張します
  • Bag –重複を許可する順序付けられていないコレクション。 サブインターフェイスには、MutableBagおよびFixedSizeBagが含まれます。 最も一般的な実装はHashBag
  • StackIterable –「後入れ先出し」の順序を維持し、逆挿入順序で要素を反復処理するコレクション。 サブインターフェイスには、MutableStackおよびImmutableStackが含まれます
  • MultiMap –各キーに複数の値を許可するキー/値のペアのコレクション

3.2. プリミティブコレクション

フレームワークは、プリミティブコレクションの膨大なセットも提供します。 それらの実装は、それらが保持するタイプにちなんで名付けられています。 それらのタイプごとに、変更可能、不変、同期、および変更不可能な形式があります。

  • プリミティブリスト
  • プリミティブセット
  • プリミティブスタック
  • プリミティブバッグ
  • プリミティブマップ
  • IntInterval

プリミティブキーまたはオブジェクトキーとプリミティブ値またはオブジェクト値のすべての可能な組み合わせをカバーする、多数のプリミティブマップフォームがあります。

簡単な注意– IntInterval は、ステップ値を使用して繰り返すことができる整数の範囲です。

4. コレクションのインスタンス化

ArrayListまたはHashSetに要素を追加するには、引数なしのコンストラクターを呼び出して、各要素を1つずつ追加することでコレクションをインスタンス化します。

Eclipseコレクションでもそれを行うことができますが、コレクションをインスタンス化し、すべての初期要素を1行で同時に提供することもできます。

FastListをインスタンス化する方法を見てみましょう。

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

同様に、 UnifiedSet をインスタンス化し、要素を newSetWith()静的メソッドに渡すことで要素を追加できます。

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

HashBagをインスタンス化する方法は次のとおりです。

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

マップをインスタンス化し、それらにキーと値のペアを追加することも同様です。 唯一の違いは、 Pair インターフェイスの実装として、キーと値のペアを newMapWith()メソッドに渡すことです。

例としてUnifiedMapを取り上げましょう。

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

JavaコレクションAPIアプローチは引き続き使用できます。

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

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

不変コレクションは変更できないため、 add() remove()などのコレクションを変更するメソッドの実装はありません。

ただし、変更できないコレクションを使用すると、これらのメソッドを呼び出すことができますが、呼び出すとUnsupportedOperationExceptionがスローされます。

5. コレクションからの要素の取得

標準のリストを使用するのと同じように、Eclipseコレクションリストの要素は、インデックスによって取得できます。

list.get(0);

また、Eclipseコレクションマップの値は、キーを使用して取得できます。

map.get(0);

getFirst()メソッドと getLast()メソッドを使用して、リストの最初と最後の要素をそれぞれ取得できます。 他のコレクションの場合、イテレータによって返される最初と最後の要素を返します。

map.getFirst();
map.getLast();

メソッドmax()および min()を使用して、自然な順序に基づいてコレクションの最大値と最小値を取得できます。

map.max();
map.min();

6. コレクションを反復処理する

Eclipseコレクションは、コレクションを反復処理するための多くの方法を提供します。 それらが何であるか、そしてそれらが実際にどのように機能するかを見てみましょう。

6.1. コレクションフィルタリング

selectパターンは、論理条件を満たすコレクションの要素を含む新しいコレクションを返します。 これは本質的にフィルタリング操作です。

次に例を示します。

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

単純なラムダ式を使用して同じことを行うことができます。

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

リジェクトパターンは反対です。 論理条件を満たさないすべての要素のコレクションを返します。

例を見てみましょう:

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

ここでは、30より大きいすべての要素を拒否します。

6.2. collect()メソッド

collect メソッドは、提供されたラムダ式によって返される結果を要素とする新しいコレクションを返します。基本的には、 map() collect()の組み合わせです。 StreamAPIから。

実際の動作を見てみましょう。

@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");
}

作成されたコレクションlastNamesには、studentリストから収集された最後の名前が含まれています。

しかし、返されたコレクションがコレクションのコレクションであり、ネストされた構造を維持したくない場合はどうなりますか?

たとえば、各学生が複数の住所を持っていて、コレクションのコレクションではなく Strings として住所を含むコレクションが必要な場合は、 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 メソッドは、要素が論理条件を満たすかどうかに応じて、コレクションの各要素を2つのコレクションのいずれかに割り当てます。

例を見てみましょう:

@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"));
}

ここで、 lazyStudents オブジェクトは、 collect()メソッドが呼び出されるまで、studentリストの要素を取得しません。

7. コレクション要素のペアリング

メソッドzip()は、2つのコレクションの要素をペアに結合することにより、新しいコレクションを返します。 2つのコレクションのいずれかが長い場合、残りの要素は切り捨てられます。

それをどのように使用できるか見てみましょう:

@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. コレクションの変換

Eclipseコレクションは、コンテナータイプを別のタイプに変換するための簡単なメソッドを提供します。 これらのメソッドは、 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コレクションとそれらが提供する機能の概要を簡単に説明しました。

このチュートリアルの完全な実装は、GitHubから入手できます。