Eclipse Collections 11.0.0は、Javaコレクションタイプと互換性のあるJava用のオープンソースコレクションライブラリであり、そのリリースにより、パフォーマンスを向上させるための新しいメソッドと機能が提供される。ClassComparer
クラスが、2つのクラスのメソッドを比較し、類似点と相違点を表示するために導入された。
当初は開発者のDon Raab氏によってGSコレクションと名付けられたが、このフレームワークは2015年12月にEclipse Foundationに寄贈され、Eclipseコレクションとしてブランド名が変更された。バージョン11.0.0は、2020年8月のバージョン10.4以来の最初のリリースである。これらのコミッターとプロジェクトリーダーによってメンテナンスされているEclipseコレクションは、JDK 8、11、17、そして18の早期アクセスに対してビルドおよびテストされている。
selectWithIndex
やrejectWithIndex
などのさまざまなメソッドが追加された。インデックスや、OrderedIterable
またはListIterable
の値に基づいて要素をフィルタするためのものである。
var exampleList = Lists.mutable.with(1, 2, 3, 4, 5);
var selectWithIndexList =
exampleList.selectWithIndex((value, index) -> value + index < 6);
assertEquals(Lists.mutable.with(1, 2, 3), selectWithIndexList);
var rejectWithIndexList =
exampleList.rejectWithIndex((value, index) -> value + index < 6);
assertEquals(Lists.mutable.with(4,5), rejectWithIndexList);
プリミティブイテラブルは、Function
を指定することにより、Comparator
を引数として持つtoSortedList
、あるいはtoSortedListBy
のいずれかを使ってMutableList
に変換できる。
var exampleSet = Sets.mutable.with(1, 2, 3, 4, 5);
var sortedList = exampleSet.toSortedList((val1, val2) -> val2 - val1);
var expected = Lists.mutable.with(5, 4, 3, 2, 1);
assertEquals(expected, sortedList);
var sortedListBy = exampleSet.toSortedListBy(Math::negateExact);
assertEquals(expected, sortedListBy);
Sirisha Pratha氏が自身のブログシリーズのパート1とパート2で詳述しているように、さまざまなメソッドがSet
に追加された。最初のメソッドはunion
で、2つのSetの要素を組み合わるものである。
var set1 = Sets.mutable.with(1, 2, 3);
var set2 = Sets.mutable.with(3, 4, 5);
var expectedSet = Sets.mutable.with(1, 2, 3, 4, 5);
assertEquals(expectedSet, set1.union(set2));
intersect
メソッドは、両方のSetに存在する要素を選択する。
var set1 = Sets.mutable.with(1, 2, 3);
var set2 = Sets.mutable.with(3, 4, 5);
var expectedSet = Sets.mutable.with(3);
assertEquals(expectedSet, set1.intersect(set2));
もう1つの新しいメソッドのdifference
は、1つ目のSetにのみ存在する要素を保持する。
var set1 = Sets.mutable.with(1, 2, 3);
var set2 = Sets.mutable.with(3, 4, 5);
var expectedSet = Sets.mutable.with(1, 2);
assertEquals(expectedSet, set1.difference(set2));
symmetricDifference
メソッドは、次の2つのSetのいずれかにのみ存在する要素を保持する。
var set1 = Sets.mutable.with(1, 2, 3);
var set2 = Sets.mutable.with(3, 4, 5);
var expectedSet = Sets.mutable.with(1, 2, 4, 5);
assertEquals(expectedSet, set1.symmetricDifference(set2));
isSubsetOf
メソッドは、最初のSetのすべての要素が2番目のSetに存在する場合にtrue
を返す。
var set1 = Sets.mutable.with(1, 2);
var set2 = Sets.mutable.with(1, 2, 3);
assertTrue(set1.isSubsetOf(set2));
assertFalse(set2.isSubsetOf(set1));
より厳密なバージョンのisProperSubsetOf
は、最初のSetのすべての要素が2番目のSetに存在するが、Setが同じでない場合にtrue
を返す。
var set1 = Sets.mutable.with(1, 2);
var set2 = Sets.mutable.with(1, 2, 3);
assertTrue(set1.isProperSubsetOf(set2));
var set3 = Sets.mutable.with(1, 2);
assertFalse(set1.isProperSubsetOf(set3));
cartesianProduct
メソッドは、最初の要素が最初のSetからの要素で、2番目の要素が2番目のSetからの要素である、すべての順序対を返す。
var set1 = IntSets.mutable.with(1, 2);
var set2 = IntSets.mutable.with(3, 4);
MutableSet<IntIntPair> expected = Sets.mutable.with(
PrimitiveTuples.pair(1, 3),
PrimitiveTuples.pair(1, 4),
PrimitiveTuples.pair(2, 4),
PrimitiveTuples.pair(2, 3));
assertEquals(expected, set1.cartesianProduct(set2).toSet());
新しく導入されたプリミティブコレクションのメソッドcontainsAny
とcontainsNone
は、機能的にanySatisfy
およびnoneSatisfy
と同等であり、メモリコストについてパフォーマンスメリットを提供する。
ImmutableIntList list = IntLists.immutable.of(1, 2, 3, 4, 5);
assertTrue(list.containsAny(3, 6));
assertTrue(list.containsAny(new IntArrayList(3, 6)));
assertTrue(list.containsNone(6, 8));
assertTrue(list.containsNone(new IntArrayList(6, 8)));
Pair
とTriple
には、値を比較するためのisEqual
とisSame
のデフォルトメソッドが含まれる。
Twin<String> equalTwin = Tuples.twin("James", "James");
assertTrue(equalTwin.isEqual());
Triplet<String> equalTriplet = Tuples.triplet("James", "James", "James");
assertTrue(equalTriplet.isEqual());
Twin<String> sameTwin = Tuples.twin("James", new String("James"));
assertFalse(sameTwin.isSame());
Triplet<String> sameTriplet =
Tuples.triplet("James", "James", new String("James"));
assertFalse(sameTriplet.isSame());
値を比較することに加えて、Pair
とTriple
をいくつかのList
タイプに変換することもできるようになった。
Twin<String> twin = Tuples.twin("James", "Mike");
MutableList<String> pairMutableList = Tuples.pairToList(twin);
FixedSizeList<String> pairFixedSizeList = Tuples.pairToFixedSizeList(twin);
ImmutableList<String> pairImmutableList = Tuples.pairToImmutableList(twin);
Triplet<String> triplet = Tuples.triplet("James", "Mike", "Patrick");
MutableList<String> tripletMutableList = Tuples.tripleToList(triplet);
FixedSizeList<String> tripletFixedSizeList =
Tuples.tripleToFixedSizeList(triplet);
ImmutableList<String> tripletImmutableList =
Tuples.tripleToImmutableList(triplet);
Bag
は、重複が含まれる可能性のある順序なしのコレクションである。これは主に、アイテムごとの発生数を判別して削除するために使用される。このバージョンでは、Bag
の新たなメソッドがいくつか提供されており、次に例を示す。
Bag<String> names = Bags.mutable.with("James", "James", "Mike", "Patrick");
これで、Bag
にアイテムが含まれているかどうかを確認できる。
assertTrue(names.anySatisfyWithOccurrences((object, value) ->
object.equals("Mike")));
assertTrue(names.noneSatisfyWithOccurrences((object, value) ->
object.equals("Simon")));
また、Bagに指定された出現回数で特定のアイテムが含まれているかどうかを確認できる。
assertTrue(names.anySatisfyWithOccurrences((object, value) ->
object.equals("James") && value == 2));
assertTrue(names.noneSatisfyWithOccurrences((object, value) ->
object.equals("James") && value == 1));
また、特定の発生回数のアイテムがあるかどうかを確認できる。
assertTrue(names.anySatisfyWithOccurrences((object, value) ->
value == 2));
assertTrue(names.noneSatisfyWithOccurrences((object, value) ->
value > 3));
Collectors2
には、toImmutableSortedBagBy
メソッドが含まれる。
var exampleList = Lists.mutable.with(1, 2, 3, 4);
ImmutableSortedBag<Integer> bag = exampleList.stream()
.collect(Collectors2.toImmutableSortedBagBy(Math::negateExact));
Comparator<Integer> comparator = Functions.toIntComparator(Math::negateExact);
ImmutableSortedMap<Integer, Integer> immutableSortedMap = exampleList.stream()
.collect(Collectors2.toImmutableSortedMap(comparator, element -> element, element -> element * 2));
var expected = SortedMaps.mutable.with(comparator, 4, 8, 3, 6, 2, 4, 1, 2);
assertEquals(expected, immutableSortedMap);
Collectors2では、toImmutableSortedMap
、toImmutableSortedMapBy
、toSortedMap
、toSortedMapBy
メソッドも提供される。
List<Integer> list = List.of(1, 2, 3);
Comparator<Integer> c =
Functions.toIntComparator(Math::negateExact);
MutableSortedMap<Integer, String> map =
list.stream().collect(
Collectors2.toSortedMap(c, e -> e, String::valueOf));
var expected = SortedMaps.mutable.with(c, 1, "1", 2, "2", 3, "3");
assertEquals(expected, map);
ImmutableMap
の新たなnewWithMap
関数とnewWithMapIterable
関数を使うと、不変のマップを作成できる。
ImmutableMap<String, Integer> immutableMap = Maps.immutable.empty();
ImmutableMap<String, Integer> resultingImmutableMap =
immutableMap.newWithMap(UnifiedMap.newMapWith(
Tuples.pair("Simon", 1),
Tuples.pair("Mike", 2)));
ImmutableMapIterable<String, Integer> immutableMapIterable =
Maps.immutable.empty();
ImmutableMapIterable<String, Integer> resultingImmutableMapIterable =
immutableMap.newWithMapIterable(UnifiedMap.newMapWith(
Tuples.pair("Simon", 1),
Tuples.pair("Mike", 2)));
一貫性を保つために、withMapIterable
メソッドとputAllMapIterable
メソッドがMutableMap
に追加された。
eclipse-collections-testutilsモジュールには、クラスを比較するためのClassComparer
が含まれる。これにより、共通のメソッドとクラス固有のメソッドを表示する一種のベン図が作成される。これらのメソッドは、オプションで実験的なSwing UIで表示できる。IntIterable.class
とRichIterable.class
を比較すると、次の結果が表示される。これらの結果には、読みやすさのために「a」で始まるメソッドのみが含まれる。
new ClassComparer().compareAndPrint(IntIterable.class, RichIterable.class);
Intersection (IntIterable, RichIterable)
----------------------------------------
a:[allSatisfy, anySatisfy, appendString, asLazy]
…
Difference (IntIterable, RichIterable)
--------------------------------------
a:[average, averageIfEmpty]
…
Difference (RichIterable, IntIterable)
--------------------------------------
a:[aggregateBy, aggregateInPlaceBy, allSatisfyWith, anySatisfyWith]
…
また、ClassComparer
ではオプションで、メソッド名、パラメータータイプ、戻り値タイプに基づいて比較するコンストラクター引数が提供される。
new ClassComparer(true, true, true)
.compareAndPrint(IntIterable.class, RichIterable.class);
Intersection (org.eclipse.collections.api.IntIterable, org.eclipse.collections.api.RichIterable)
------------------------------------------------------------------------------------------------
a:[appendString(Appendable):void, appendString(Appendable, String):void, appendString(Appendable, String, String, String):void]
…
Difference (org.eclipse.collections.api.IntIterable, org.eclipse.collections.api.RichIterable)
----------------------------------------------------------------------------------------------
a:[allSatisfy(IntPredicate):boolean, anySatisfy(IntPredicate):boolean, asLazy():LazyIntIterable, average():double, averageIfEmpty(double):double]
…
Difference (org.eclipse.collections.api.RichIterable, org.eclipse.collections.api.IntIterable)
----------------------------------------------------------------------------------------------
a:[aggregateBy(Function, Function0, Function2):MapIterable, aggregateBy(Function, Function0, Function2, MutableMapIterable):MutableMapIterable, aggregateInPlaceBy(Function, Function0, Procedure2):MapIterable, allSatisfy(Predicate):boolean, allSatisfyWith(Predicate2, Object):boolean, anySatisfy(Predicate):boolean, anySatisfyWith(Predicate2, Object):boolean, asLazy():LazyIterable]
…
toList
やtoSortedSet
などの可変コンバーターメソッドはかなり前から利用できたが、不変のメソッドは利用できなかった。toImmutable
メソッドを使って不変に変換することは可能であったが、.toList().toImmutable()
という2つのステップが必要になる場合があった。可変に対応するものとして一貫性を向上させるために、toImmutableList
、toImmutableSet
、toImmutableBag
がRichIterable
に追加され、他のメソッドが将来続く可能性がある。
変更点の全リストは、GitHubリリースページで確認できる。