BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース Eclipseコレクション11.0.0を特徴付ける新たなAPIと機能

Eclipseコレクション11.0.0を特徴付ける新たなAPIと機能

ブックマーク

原文(投稿日:2022/02/17)へのリンク

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の早期アクセスに対してビルドおよびテストされている。

selectWithIndexrejectWithIndexなどのさまざまなメソッドが追加された。インデックスや、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());

新しく導入されたプリミティブコレクションのメソッドcontainsAnycontainsNoneは、機能的に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)));

PairTripleには、値を比較するためのisEqualisSameのデフォルトメソッドが含まれる。

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

値を比較することに加えて、PairTripleをいくつかの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では、toImmutableSortedMaptoImmutableSortedMapBytoSortedMaptoSortedMapByメソッドも提供される。

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.classRichIterable.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]
…

toListtoSortedSetなどの可変コンバーターメソッドはかなり前から利用できたが、不変のメソッドは利用できなかった。toImmutableメソッドを使って不変に変換することは可能であったが、.toList().toImmutable()という2つのステップが必要になる場合があった。可変に対応するものとして一貫性を向上させるために、toImmutableListtoImmutableSettoImmutableBagRichIterable追加され、他のメソッドが将来続く可能性がある。

変更点の全リストは、GitHubリリースページで確認できる。

作者について

この記事に星をつける

おすすめ度
スタイル

こんにちは

コメントするには InfoQアカウントの登録 または が必要です。InfoQ に登録するとさまざまなことができます。

アカウント登録をしてInfoQをお楽しみください。

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

コミュニティコメント

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

HTML: a,b,br,blockquote,i,li,pre,u,ul,p

BT