GS Collections v6.0.0 Release Notes
Release Date: 2015-02-09 // about 9 years ago-
Binaries
Javadoc
JDiff
Differences between 5.1.0 and 6.0.0
Acquiring GS Collections
Maven
\<dependency\> \<groupId\>com.goldmansachs\</groupId\> \<artifactId\>gs-collections-api\</artifactId\> \<version\>6.0.0\</version\> \</dependency\> \<dependency\> \<groupId\>com.goldmansachs\</groupId\> \<artifactId\>gs-collections\</artifactId\> \<version\>6.0.0\</version\> \</dependency\> \<dependency\> \<groupId\>com.goldmansachs\</groupId\> \<artifactId\>gs-collections-testutils\</artifactId\> \<version\>6.0.0\</version\> \<scope\>test\</scope\> \</dependency\> \<dependency\> \<groupId\>com.goldmansachs\</groupId\> \<artifactId\>gs-collections-forkjoin\</artifactId\> \<version\>6.0.0\</version\> \</dependency\>
Ivy
\<dependency org="com.goldmansachs" name="gs-collections-api" rev="6.0.0" /\> \<dependency org="com.goldmansachs" name="gs-collections" rev="6.0.0" /\> \<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="6.0.0" /\> \<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="6.0.0"/\>
๐ New Functionality
RichIterable API
RichIterable.each(Procedure)
Java 8 introduced
Iterable.forEach(Consumer)
which can cause problems for users ofRichIterable.forEach(Procedure)
.Consumer
andProcedure
have the same shape, so passing in a lambda is ambiguous.FastList.newListWith(1, 2, 3).forEach(System.out::println);
This code fails with the following compiler error.
Error: reference to forEach is ambiguous both method forEach(java.util.function.Consumer\<? super T\>) in java.lang.Iterable and method forEach(com.gs.collections.api.block.procedure.Procedure\<? super T\>) in com.gs.collections.impl.list.mutable.FastList match
โช You can work around this problem by using a cast,
Procedures.cast()
, or by usingRichIterable.each(Procedure)
which behaves exactly likeInternalIterable.forEach(Procedure)
.FastList.newListWith(1, 2, 3).forEach((Procedure\<? super Integer\>) System.out::println);FastList.newListWith(1, 2, 3).forEach(Procedures.cast(System.out::println));FastList.newListWith(1, 2, 3).each(System.out::println);
RichIterable.tap(Procedure): RichIterable
Executes the
Procedure
for each element in the iterable and returns theRichIterable
. Similar toRichIterable.forEach(Procedure)
andRichIterable.each(Procedure)
but returnsthis
.LazyIterable.tap(Procedure): LazyIterable
LazyIterable.tap(Procedure)
overridesRichIterable.tap(Procedure)
and executes lazily. It is useful to "tap into" a method chain, executing aProcedure
on every element of theLazyIterable
without ending the chain or forcing evaluation.RichIterable\<String\> list = Lists.mutable.of("One", "Two", "Three", "Four"); list.asLazy() .tap(each -\> System.out.println(each + " --(Each element prints this)")) .select(StringPredicates.contains("o")) .tap(selected -\> System.out.println(selected + " --(Only selected element prints this)")) .collect(String::toUpperCase) .tap(collected -\> System.out.println(collected + " --(Collected element prints this)")) .each(a -\> {}); // force evaluation
๐จ Prints
One --(Each element prints this)Two --(Each element prints this)Two --(Only selected element prints this)TWO --(Collected element prints this)Three --(Each element prints this)Four --(Each element prints this)Four --(Only selected element prints this)FOUR --(Collected element prints this)
RichIterable.toSortedBag(), RichIterable.toSortedBag(Comparator), and RichIterable toSortedBagBy(Function)
RichIterable.toSortedBag()
converts the collection to aMutableSortedBag
implementation and sorts it using the natural order of the elements.RichIterable.toSortedBag(Comparator)
sorts using theComparator
parameter.RichIterable.toSortedBagBy(Function)
sorts based on the natural order of the attribute returned by theFunction
parameter.RichIterable.groupByUniqueKey(Function): MapIterable.
๐ป Similar to
RichIterable.groupBy(Function)
. The keys returned by theFunction
must be unique, otherwise an exception is thrown. Since the keys are unique,groupByUniqueKey()
returns aMapIterable
instead of aMultimap
.RichIterable.sumBy(Int|Long|Float|Double)
RichIterable.sumByInt(Function<T, V> groupBy, IntFunction<? super T> function): ObjectLongMap<V>
RichIterable.sumByLong(Function<T, V> groupBy, LongFunction<? super T> function): ObjectLongMap<V>
RichIterable.sumByFloat(Function<T, V> groupBy, FloatFunction<? super T> function): ObjectDoubleMap<V>
RichIterable.sumByDouble(Function<T, V> groupBy, DoubleFunction<? super T> function): ObjectDoubleMap<V>
Groups the elements in the
RichIterable
by the groupByFunction
. Each group is converted to numbers using the primitive function and then summed.sumByInt()
andsumByLong()
returnObjectLongMap
.sumByFloat()
andsumByDouble()
returnObjectDoubleMap
.OrderedIterable API
OrderedIterable interface for order dependent functionality.
An
OrderedIterable
is aRichIterable
with some meaningful order, such as insertion order, access order, or sorted order.ReversibleIterable
andSortedIterable
now extendOrderedIterable
.Several methods were pulled up to
OrderedIterable
.indexOf(Object)
takeWhile(Predicate)
,dropWhile(Predicate)
, andpartitionWhile(Predicate)
distinct()
toStack()
๐ Other methods on
InternalIterable
andRichIterable
are now deprecated because they imply a meaningful order which not all containers have. These methods are overridden onOrderedIterable
so that the deprecation warning will not appear on ordered collections.getFirst()
andgetLast()
forEach(startIndex, endIndex, procedure)
forEachWithIndex(ObjectIntProcedure)
forEachWithIndex(fromIndex, toIndex, objectIntProcedure)
OrderedIterable.corresponds(OrderedIterable, Predicate2).
Returns true if both
OrderedIterable
s have the same length and the predicate returnstrue
for all elements e1 of the currentOrderedIterable
and e2 of the otherOrderedIterable
.The predicate is evaluated for pairs of elements at the same position in both
OrderedIterable
s. Thecorresponds()
method short circuits as soon as it finds a pair of elements which do not correspond.MutableList\<Integer\> integers1 = FastList.newListWith(1, 2, 2, 3, 3, 3, 4, 4, 4, 4);MutableList\<Integer\> integers2 = FastList.newListWith(2, 3, 3, 4, 4, 4, 5, 5, 5, 5);Assert.assertTrue(integers1.corresponds(integers3, Predicates2.lessThan()));
OrderedIterable.detectIndex(Predicate).
Returns the index of the first element which satisfies the
Predicate
or-1
if no elements do. ThedetectIndex()
method short circuits as soon as it finds an element which satisfies thePredicate
.ListIterable\<Integer\> list = FastList.newListWith(1, 1, 2, 2, 3, 3);Assert.assertEquals(2, list.detectIndex(integer -\> integer == 2));Assert.assertEquals(-1, list.detectIndex(integer -\> integer == 4));
ReversibleIterable API
ReversibleIterable.detectLastIndex(Predicate).
Returns the index of the last element which satisfies the
Predicate
or-1
if no elements do. ThedetectLastIndex()
method iterates in reverse order and short circuits as soon as it finds an element which satisfies thePredicate
.ListIterable\<Integer\> list = FastList.newListWith(1, 1, 2, 2, 3, 3);Assert.assertEquals(3, list.detectLastIndex(integer -\> integer == 2));Assert.assertEquals(-1, list.detectLastIndex(integer -\> integer == 4));
ReversibleIterable.distinct().
Same as
ReversibleIterable.distinct()
for primitive collections.ReversibleIterable.take(int n) and ReversibleIterable.drop(int n).
take()
Returns the first
n
elements of the iterable or all the elements in the iterable ifn
is greater than the length of the iterable.MutableList\<Integer\> list = FastList.newListWith(1, 2, 3, 4, 5);Assert.assertEquals(FastList.newList(), list.take(0));Assert.assertEquals(FastList.newListWith(1, 2, 3), list.take(3));Assert.assertEquals(FastList.newListWith(1, 2, 3, 4, 5), list.take(6));
โฌ๏ธ drop()
Returns an iterable after skipping the first
n
elements or an empty iterable ifn
is greater than the length of the iterable.MutableList\<Integer\> list = FastList.newListWith(1, 2, 3, 4, 5);Assert.assertEquals(FastList.newListWith(1, 2, 3, 4, 5), list.drop(0));Assert.assertEquals(FastList.newListWith(4, 5), list.drop(3));Assert.assertEquals(FastList.newListWith(), list.drop(6));
ParallelIterable API
ListIterable.asParallel(), SetIterable.asParallel(), and SortedSetIterable.asParallel().
In 5.0,
asParallel()
was added toFastList
andUnifiedSet
. Now it's on the interfaces ListIterable, SetIterable and SortedSetIterable as well.ListIterable\<Person\> people = ...;ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());int batchSize = 10\_000;ParallelListIterable\<Person\> peopleParallel = people.asParallel(threadPool, batchSize);
min(), max(), minBy(), and maxBy() on ParallelIterable.
Similar to the same methods on
RichIterable
. These methods force evaluation.ParallelListIterable\<Person\> peopleParallel = people.asParallel(threadPool, batchSize);Integer youngestAge = peopleParallel.collect(Person::getAge).min();Integer oldestAge = peopleParallel.collect(Person::getAge).max();Person youngestPerson = peopleParallel.minBy(Person::getAge);Person oldestPerson = peopleParallel.maxBy(Person::getAge);
sumOfInt(), sumOfFloat(), sumOfLong(), sumOfDouble() on ParallelIterable.
Similar to the same methods on
RichIterable
. These methods force evaluation.ParallelListIterable\<Person\> peopleParallel = people.asParallel(threadPool, batchSize);long sum1 = peopleParallel.sumOfInt(Person::getIntAttribute);long sum2 = peopleParallel.sumOfLong(Person::getLongAttribute);double sum3 = peopleParallel.sumOfFloat(Person::getFloatAttribute);double sum4 = peopleParallel.sumOfDouble(Person::getDoubleAttribute);
Multimap API
Constructors for Multimaps that take Iterable<Pair<K, V>>.
ListIterable\<Pair\<Integer, String\>\> pairs = ...;Multimap\<Integer, String\> actual = FastListMultimap.newMultimap(pairs);
MutableMultimap.add(Pair).
Similar to
MutableMultimap.put(K, V)
but takesPair<K, V>
instead.Multimap.forEachKeyMultiValues(Procedure2<K, ? super Iterable>)
Similar to
forEachKeyValue(Procedure2<K, V>)
but theProcedure2
gets invoked on each group of values instead of each individual value.Multimap.selectKeysValues(Predicate2<? super K, ? super V>) and Multimap.rejectKeysValues(Predicate2<? super K, ? super V>).
๐ Similar to
RichIterable.select()
andRichIterable.reject()
but thePredicate2
is evaluated against each key/value pair. The implementation of thePredicate2
is free to ignore either the key or the value.Multimap.selectKeysMultiValues(Predicate2<? super K, ? super Iterable>) and Multimap.rejectKeysMultiValues(Predicate2<? super K, ? super Iterable>).
Similar to
Multimap.selectKeysValues()
andMultimap.rejectKeysValues()
but thePredicate2
takes (K, Iterable) pairs instead of (K, V) pairs.Multimap.collectKeysValues(Function2<? super K, ? super V, Pair<K2, V2>>).
Similar to
RichIterable.collect()
but theFunction2
is applied to each key/value pair.Multimap.collectValues(Function<? super V, ? extends V2>)
Similar to
Multimap.collectKeysValues()
but only transforms keys. It is more efficient than usingMultimap.collectKeysValues()
and passing through the keys unchanged.Multimap<K, V>.flip(): Multimap<V, K>.
Returns a new
Multimap
where the positions of the keys and values are swapped.Other new API
Unify the map interface hierarchy through new interfaces MutableMapIterable and ImmutableMapIterable.
MutableMap
,MutableSortedMap
, andMutableBiMap
now extend a common interfaceMutableMapIterable
.ImmutableMap
,ImmutableSortedMap
, andImmutableBiMap
now extend a common interfaceImmutableMapIterable
. TheSetIterable
andBag
hierarchy had similar changes.๐ MutableIterator.remove()
๐
Mutable<Primitive>Iterator
is a new subclass of<Primitive>Iterator
that adds theremove()
method. It behaves similarly toIterator.remove()
, but does not appear on immutable primitive containers and thus doesn't throwUnsupportedOperationException
. Immutable containers continue to return the read-only<Primitive>Iterator
.Bag.topOccurrences() and Bag.bottomOccurrences().
Bag.topOccurrences()
returns the most frequently occurring item.Bag.bottomOccurrences()
returns the least frequently occurring item. In the event of a tie, all tied items are returned.ImmutableList.subList(fromIndex, toIndex): ImmutableList.
Similar to
List.subList()
but returns anImmutableList
.Primitive forms of MutableList.sortThisBy().
Similar to
sortThisBy(Function)
but taking primitive functions. For example,MutableList\<T\> sortThisByInt(IntFunction\<? super T\> function);MutableList\<T\> sortThisByFloat(FloatFunction\<? super T\> function);...
Pair.swap().
Returns a new
Pair
with the two elements transposed.Functions.swappedPair().
Returns a
Function
which swaps the two elements in aPair
. Similar to Pair::swap but doesn't rely on Java 8.StringIterate.chunk(int).
๐ Breaks up a String into fixed size chunks. Similar to
RichIterable.chunk()
, but forStrings
rather than collections.๐ New Containers
ImmutableBiMap
ImmutableBiMap
s can be created by using theBiMaps
factory or by callingMutableBiMap.toImmutable()
.MutableBiMap\<Integer, Character\> biMap = ...;ImmutableBiMap\<Integer, Character\> characters = biMap.toImmutable();
MultiReaderFastListMultimap, MultiReaderUnifiedSetMultimap, and MultiReaderHashBagMultimap.
Thread-safe
Multimaps
backed byConcurrentMutableMap
s of multi-reader collections.โ Tests
โ JUnit Runner for interfaces containing concrete tests. New test suite leveraging virtual extension methods.
โ A new JUnit
Runner
namedJava8Runner
that extends the standard test runner by looking for tests in interfaces in addition to classes. Tests in interfaces are default methods annotated with@Test
. For example:@Testdefault void MutableList\_sortThis() { MutableList\<Integer\> mutableList = this.newWith(5, 1, 4, 2, 3); MutableList\<Integer\> sortedList = mutableList.sortThis(); assertSame(mutableList, sortedList); assertEquals(Lists.immutable.with(1, 2, 3, 4, 5), sortedList); }
โ This allows for a form of multiple inheritance in tests. For example, a
MutableList
is both aMutableCollection
and aListIterable
. Any assertions aboutMutableCollection
s andListIterable
s should be true forMutableList
s as well. Thus, the test interfaceMutableListTestCase
extends bothMutableCollectionTestCase
andListIterableTestCase
.โ
unit-tests-java8
is a new test suite containing over 50 new test classes and 60 new test interfaces.โ Additional JMH Tests
๐ Performance tests covering
min
,max
,minBy
,maxBy
,sumOf
, andsumBy
.Optimizations
โก๏ธ Optimize primitive hash maps with keys and values of the same primitive type.
Primitive hash maps with keys and values of the same primitive type (
IntIntHashMap
,DoubleDoubleHashMap
, etc.), keys and values are now stored in a single array of double the length.๐ This yields a small memory savings and a speed increase in larger maps. The corresponding JMH performance tests are
IntIntMapTest
andLongIntMapTest
.โก๏ธ Optimize code paths that unnecessarily use iterator by delegating to IterableIterate by delegating to forEach() instead.
๐ Bug Fixes
- โ Make ArrayListAdapterSerializationTest more robust for future versions of Java. Fixes #12.
- ๐ Fix array index bug in ArrayList.sortThis(). Fixes #16.
- ๐ Fix ObjectHashMap.injectInto() to include sentinels values.
- ๐ Fix ImmutableSortedMap.entrySet() to return entries sorted by key.
- ๐ Fix CountSetTest to delegate to CountSetScalaTest. Fixes #15.
- ๐ Fix concurrency issue in the aggregateBy tests.
- ๐ Fix the iteration order of several iteration patterns.
- ๐ Use the Kahan summation algorithm to handle double and float precision in sumOf().
- ๐ Fix looping logic in SortedSetIterable.forEach() and SortedSetIterable.forEachWithIndex() with fromIndex and toIndex.
- ๐ Fix CompositeFastList.size() to execute in constant time.
- ๐ Fix ListAdapter.reverseThis() to run in linear time.
- ๐ Fix ListIterate.toArray(list, target, startIndex, sourceSize) and ListIterate.getLast() to run in linear time.
- ๐ Fix UnifiedSet.getLast() and UnifiedSetWithHashingStrategy.getLast() to return the last instead of the first element.