GS Collections v5.0.0 Release Notes
Release Date: 2014-03-21 // about 10 years ago-
Binaries
Javadoc
JDiff
API differences between 4.0.0 and 5.0.0
Acquiring GS Collections
Maven
\<dependency\> \<groupId\>com.goldmansachs\</groupId\> \<artifactId\>gs-collections-api\</artifactId\> \<version\>5.0.0\</version\> \</dependency\> \<dependency\> \<groupId\>com.goldmansachs\</groupId\> \<artifactId\>gs-collections\</artifactId\> \<version\>5.0.0\</version\> \</dependency\> \<dependency\> \<groupId\>com.goldmansachs\</groupId\> \<artifactId\>gs-collections-testutils\</artifactId\> \<version\>5.0.0\</version\> \<scope\>test\</scope\> \</dependency\> \<dependency\> \<groupId\>com.goldmansachs\</groupId\> \<artifactId\>gs-collections-forkjoin\</artifactId\> \<version\>5.0.0\</version\> \</dependency\>
Ivy
\<dependency org="com.goldmansachs" name="gs-collections-api" rev="5.0.0" /\> \<dependency org="com.goldmansachs" name="gs-collections" rev="5.0.0" /\> \<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="5.0.0" /\> \<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="5.0.0"/\>
๐ New Functionality
Parallel-Lazy Iteration
๐ Previous versions of GS Collections included parallel evaluation and lazy evaluation as separate features. Parallel-eager utility has been available through the
ParallelIterate
utility class. Serial-lazy evaluation has been available throughLazyIterable
, the view returned byRichIterable.asLazy()
. GS Collections 5.0 adds parallel-lazy evaluation throughParallelIterable
, the view returned byasParallel(ExecutorService, int batchSize)
. The methodasParallel
is not on interfaces likeRichIterable
yet, but rather on a few supported collections, includingFastList
andUnifiedSet
.FastList\<Integer\> integers = FastList.newListWith(1, 2, 3, 4, 5, 6, 7, 8, 9);ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());int batchSize = 2;ParallelListIterable\<Integer\> parallelListIterable = integers.asParallel(threadPool, batchSize);ParallelListIterable\<Integer\> evenNumbers = parallelListIterable.select(each -\> each % 2 == 0); // deferred evaluationParallelListIterable\<String\> evenStrings = evenNumbers.collect(Object::toString); // deferred evaluationMutableList\<String\> strings = evenStrings.toList(); // forced evaluationthreadPool.shutdown();Assert.assertEquals(FastList.newListWith("2", "4", "6", "8"), strings);
The calls to
select
andcollect
are lazy, indicated by the fact that they return subclasses ofParallelIterable
. The call totoList()
forces evaluation.๐ The two parameters to
asParallel
are used to configure parallelism. The code example above sets up a thread pool with one thread per core, which is appropriate for CPU bound tasks. It's possible to configure the thread pool for IO bound tasks, and to share thread pools between multiple calls toasParallel.
The batch size determines the number of elements from the backing collection that get processed by each task submitted to the thread pool. The appropriate batch size for CPU-bound tasks will be much larger, usually 10,000 to 100,000. The right batch size should be determined through thorough performance testing.๐ NOTE: The new parallel-lazy API is experimental and is tagged as
@Beta
. Until we remove the@Beta
annotation, we reserve the right to make incompatible changes to the parallel-lazy API even in minor versions of GS Collections.API
anySatisfyWith
,allSatisfyWith
,noneSatisfyWith
,countWith
,partitionWith
,detectWith
, anddetectWithIfNone
onRichIterable
These are the two-argument forms of
anySatisfy
,allSatisfy
,noneSatisfy
,count
,partition
,detect
anddetectIfNone
. They take aPredicate2
instead of aPredicate
, and a second argument, which is passed as the second argument to thePredicate2
. The two argument forms allow reusing some code blocks that would otherwise have one differing parameter, resulting in less garbage creation. Some of these methods already existed onMutableCollection
and were pulled up toRichIterable
. Here is a comparison betweenanySatisfy
andanySatisfyWith
.Assert.assertTrue(this.newWith(1, 2, 3).anySatisfyWith(Predicates2.equal(), 2));Assert.assertTrue(this.newWith(1, 2, 3).anySatisfy(Predicates.equal(2)));
RichIterable.collect<Primitive>(<Primitive>Function, Mutable<Primitive>Collection target)
The new overload
RichIterable.collect<Primitive>(<Primitive>Function, Mutable<Primitive>Collection target)
is similar tocollect<Primitive>(<Primitive>Function)
, except that the results are gathered into the specified target collection.ListIterable.toImmutable()
,SortedSetIterable.toImmutable()
,UnsortedSetIterable.toImmutable()
,SortedMapIterable.toImmutable()
,UnsortedMapIterable.toImmutable()
,StackIterable.toImmutable()
Previously,
toImmutable()
only existed onMutableCollection
s. It's now available on the read-only interfaces as well. When called on an immutable collection, it returns the same instance.MutableStack\<Integer\> mutableStack = Stacks.mutable.with(1, 2, 3);Verify.assertInstanceOf(ImmutableStack.class, mutableStack.toImmutable());Assert.assertNotSame(mutableStack, mutableStack.toImmutable());StackIterable\<Integer\> immutableStack = Stacks.immutable.with(1, 2, 3);Assert.assertSame(immutableStack, immutableStack.toImmutable());
ListIterable.binarySearch(T)
andListIterable.binarySearch(T, Comparator)
Similar to
java.util.Collections.binarySearch
, but available from the object-oriented API.LazyIterable.distinct()
andLazyIterate.distinct(Iterable)
Similar to
toSet(),
but returns aLazyIterable
(does not force evaluation).MapIterable.flip()
Returns a new associative array where the position of the keys and values have been flipped. Since the values in the
MapIterable
are not necessarily unique,flip()
returns aMultimap
instead of aMapIterable
. Since the keys in theMapIterable
are unique,flip()
returns aSetMultimap
instead of the more generalMultimap
interface. In summary,MapIterable<K, V>.flip()
returnsSetMultimap<V, K>
.MutableSetMultimap\<String, String\> expected = UnifiedSetMultimap.newMultimap(); expected.put("odd", "One"); expected.put("even", "Two"); expected.put("odd", "Three"); expected.put("even", "Four");Assert.assertEquals(expected, UnifiedMap.newWithKeysValues("One", "odd", "Two", "even", "Three", "odd", "Four", "even").flip());
MapIterable.flipUniqueValues()
Similar to
MapIterable.flip()
but asserts that the values in theMapIterable
are unique and thus returnsMapIterable
instead ofMultimap
. ThrowsIllegalArgumentException
if theMapIterable
contains duplicate values.MapIterable\<Integer, String\> map = this.newMapWithKeysValues(1, "1", 2, "2", 3, "3");MapIterable\<String, Integer\> flip = map.flipUniqueValues();Assert.assertEquals(UnifiedMap.newWithKeysValues("1", 1, "2", 2, "3", 3), flip);
MutableMap.getIfAbsentPut(K key, V value)
Gets and returns the value in the map at the specified key. If the map does not contain the key,
getIfAbsentPut()
puts the value in the map and returns it. Similar togetIfAbsentPut(K key, Function0<? extends V> function)
, but takes in a value directly instead of a value factory (Function0
).MutableMap\<Integer, String\> map = UnifiedMap.newWithKeysValues(1, "1", 2, "2", 3, "3");Assert.assertEquals("4", map.getIfAbsentPut(4, "4")); // mutatesAssert.assertEquals("3", map.getIfAbsentPut(3, "5")); // does not mutateVerify.assertContainsKeyValue(3, "3", map);Verify.assertContainsKeyValue(4, "4", map);
MutableMap.add(Pair<K, V>)
โ Adds the key-value pair to the map. It's a convenience method for working with
Pair
s, similar toput(K, V)
.MutableMap\<String, Integer\> map = this.newMapWithKeyValue("A", 1);Assert.assertEquals(Integer.valueOf(1), map.add(Tuples.pair("A", 3)));Assert.assertNull(map.add(Tuples.pair("B", 2)));Verify.assertMapsEqual(UnifiedMap.newWithKeysValues("A", 3, "B", 2), map);
MutableBag.setOccurrences(T item, int occurrences)
Mutates the bag to contain the given number of occurrences of the item. Returns
true
if the bag has been modified as a result of the call tosetOccurrences()
.MutableBag\<String\> bag = HashBag.newBag();MutableBag\<String\> expected = this.newWith("betamax-tape", "betamax-tape");Assert.assertTrue(bag.setOccurrences("betamax-tape", 2));Assert.assertEquals(expected, bag);
ListIterate.reverseForEachWithIndex(List, ObjectIntProcedure)
Iterates over the list in reverse order executing the
ObjectIntProcedure
for each element. The index passed into theObjectIntProcedure
is the actual index of the range.Primitive API
Mutable<Primitive>Collection.retainAll
Like
Collection.retainAll
, but for primitive collections. There are two variants, one that takes a<Primitive>Iterable
, and another that takes varargs.Assert.assertTrue(collection.retainAll(IntArrayList.newListWith(1, 2, 5)));Assert.assertEquals(this.newMutableCollectionWith(1, 2), collection);MutableIntCollection collection = this.newMutableCollectionWith(1, 2, 3);Assert.assertFalse(collection.retainAll(1, 2, 3));Assert.assertEquals(this.newMutableCollectionWith(1, 2, 3), collection);
keysView()
andkeyValuesView()
on primitive mapsReturns a lazy view of keys or key/value pairs respectively.
๐
keySet()
andvalues()
on synchronized, unmodifiable, and immutable primitive maps๐ These methods already existed on the API but threw
UnsupportedOperationException
s in places. They are fully supported now.addToValue(key, amount)
on mutable primitive mapsโ Adds the given amount to the value at the given key and returns the updated value. This method exists only for maps where the values are numeric types (not
boolean
orObject
).MutableByteIntMap map = new ByteIntHashMap();Assert.assertEquals(1, map.addToValue((byte) 0, 1));Assert.assertEquals(ByteIntHashMap.newWithKeysValues((byte) 0, 1), map);Assert.assertEquals(11, map.addToValue((byte) 0, 10));Assert.assertEquals(ByteIntHashMap.newWithKeysValues((byte) 0, 11), map);
Mutable<Primitive>ObjectMap.putAll(<Primitive>ObjectMap)
putAll()
was already implemented onMutableObject<Primitive>Map
and<Primitive><Primitive>Map
. This rounds out the API.Reversible<Primitive>Iterable.asReversed()
Returns a reversed view of the primitive iterable. Like
ReversibleIterable.asReversed()
, but for the primitive API.Reversible<Primitive>Iterable.toReversed()
Returns a reversed copy of the primitive iterable. Like
asReversed()
but executes eagerly.<Primitive>Iterable.injectInto
injectInto
was already implemented on primitive collections and has now been pulled up to the<Primitive>Iterable
interfaces.IntIterable arrayList = IntArrayList.newListWith(1, 2, 3);MutableInteger sum = arrayList.injectInto(new MutableInteger(0), new ObjectIntToObjectFunction\<MutableInteger, MutableInteger\>() { public MutableInteger valueOf(MutableInteger object, int value) { return object.add(value); } });Assert.assertEquals(new MutableInteger(6), sum);
Code Block Factory Methods
Functions.nullSafe(Function)
Returns a null-safe wrapper around the given
Function
. The wrapper delegates to thevalueOf()
method of the delegateFunction
only if the parameter is notnull
, otherwise it returnsnull
or the providednull
replacement value.MutableList\<Integer\> squares = FastList.newListWith(1, 2, null, 3).collect(Functions.nullSafe(Functions.squaredInteger()));Assert.assertEquals(FastList.newListWith(1, 4, null, 9), squares);MutableList\<Integer\> squaresWithNullValue =FastList.newListWith(1, 2, null, 3).collect(Functions.nullSafe(Functions.squaredInteger(), 0));Assert.assertEquals(FastList.newListWith(1, 4, 0, 9), squaresWithNullValue);
Functions2.integerAddition()
Creates a
Function2
that takes in twoInteger
s as parameters and returns their sum.HashingStrategies.chain(HashingStrategy...)
Takes a vararg number of hashing strategies and returns a wrapper
HashingStrategy
that considers objects as equal if all the delegate strategies consider them equal. The hashcode is computed using a strategy similar to code-generatedhashCode()
methods. It start with the first delegate strategy's computed hashcode, and then repeatedly multiplies the accumulated hashcode by31
and adds the next computed hashcode for each remaining delegate strategy.HashingStrategies.identityStrategy()
Returns a
HashingStrategy
that considers objects as equal only if they are the same object. It uses reference equality in the implementation ofequals
, andSystem.identityHashCode
in the implementation ofcomputeHashCode
.HashingStrategies.fromFunctions(Function, Function)
andHashingStrategies.fromFunctions(Function, Function, Function)
Creates a
HashingStrategy
from eachFunction
, chains them, and returns the chain.HashingStrategies.from<Primitive>Function
โก๏ธ Similar to
HashingStrategies.fromFunction(Function)
but optimized for primitives. Implemented in a way that calls toequals
andcomputeHashCode
do not create any garbage.ReversibleIterable
andSortedIterable
InterfacesTwo new interfaces have been introduced in the GS Collections Hierarchy.
ReversibleIterable
is an ordered iterable which can be traversed efficiently forwards or backwards.ReversibleIterable
has extra API for iterating from the end likeasReversed()
andreverseForEach()
. Lists are the most commonReversibleIterable
s, andListIterable
extendsReversibleIterable
.SortedIterable
, is an ordered iterable where the elements are stored in sorted order. Its methodcomparator()
returns theComparator
used to sort the elements, ornull
if they are sorted in natural order.SortedSetIterable
andSortedBag
extendSortedIterable
.๐ Changes in the
Bag
Interface HierarchyThe inheritance hierarchy of
Bag
s is now more consistent withSet
s. We introduced a new interfaceUnsortedBag
, as a sibling ofSortedBag
.Bag
no longer overridescollect
, so it returnsRichIterable
instead ofBag
.SortedBag.collect
returnsListIterable
instead ofBag
.UnsortedBag.collect
returnsUnsortedBag
, which means the implementations ofUnsortedBag.collect
are unchanged. The new interface structure is as follows:The change to the interface hierarchy changed the serialized forms of
TreeBag
andUnmodifiableSortedBag
.๐ Changes to serialized forms
๐ Serialized form of synchronized and unmodifiable collections
๐ The hierarchy of synchronized and unmodifiable collections has been changed slightly.
AbstractSynchronizedMutableCollection
has been extracted fromSynchronizedMutableCollection
, and all the classes that used to extendSynchronizedMutableCollection
likeSynchronizedMutableList
andSynchronizedMutableSet
now extendAbstractSynchronizedMutableCollection
directly. Similar changes have been made to the unmodifiable collections.Serialized form of immutable collections
The serialized forms of
ImmutableSet
,ImmutableBag
andImmutableMap
implementations have been changed.The
ImmutableSet
implementations now use a proxy class for serialization.๐ฆ The implementations of
ImmutableMap
andImmutableBag
already used proxy classes for serialization. These proxy classes were inner classes insideAbstractImmutableMap
andAbstractImmutableBag
respectively. These proxy classes were moved to top level, package private classes.