Releases: goldmansachs/gs-collections
7.0.3 (February 2016)
Bug Fixes
- Fixed memory leak in HashBiMap.
- Fixed incorrect code path in key collision handling and keyset iterator based remove operation in primitive Maps with Hashing Strategy.
Acquiring Eclipse Collections
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>7.0.3</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>7.0.3</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>7.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>7.0.3</version>
</dependency>
Gradle
compile 'com.goldmansachs:gs-collections-api:7.0.3'
compile 'com.goldmansachs:gs-collections:7.0.3'
testCompile 'com.goldmansachs:gs-collections-testutils:7.0.3'
compile 'com.goldmansachs:gs-collections-forkjoin:7.0.3'
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="7.0.3" />
<dependency org="com.goldmansachs" name="gs-collections" rev="7.0.3" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="7.0.3" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="7.0.3"/>
7.0.1 (December 2015)
Bug Fixes
Fixed UnifiedSet.ChainedBucket.removeLongChain() method to handle many collisions in one bucket.
Acquiring Eclipse Collections
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>7.0.1</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>7.0.1</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>7.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>7.0.1</version>
</dependency>
Gradle
compile 'com.goldmansachs:gs-collections-api:7.0.1'
compile 'com.goldmansachs:gs-collections:7.0.1'
testCompile 'com.goldmansachs:gs-collections-testutils:7.0.1'
compile 'com.goldmansachs:gs-collections-forkjoin:7.0.1'
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="7.0.1" />
<dependency org="com.goldmansachs" name="gs-collections" rev="7.0.1" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="7.0.1" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="7.0.1"/>
7.0.0 (October 2015)
Acquiring GS Collections
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>7.0.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>7.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>7.0.0</version>
</dependency>
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="7.0.0" />
<dependency org="com.goldmansachs" name="gs-collections" rev="7.0.0" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="7.0.0" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="7.0.0"/>
Breaking Changes
MutableCollection.removeIf()
now returnsboolean
.- Sorted sets, bags, and maps implement
ReversibleIterable
. AddedOrderedMap
interface to represent a linked hash map. - Overrode
BiMap.partition()
to returnPartitionUnsortedSet
. UnifiedMap
andUnifiedSet
now throw if constructed with a load factor greater than 1.toStringOfItemToCount()
inImmutableEmptyBag
now consistent with other Bags.
Returns"{}"
instead of""
New Functionality
Primitive Collections
<Primitive>List.binarySearch()
Fixes #20
ObjectPrimitiveHashMapWithHashingStrategy
Similar to ObjectPrimitiveHashMap
but uses a HashingStrategy
to hash and compare keys. Analogous to UnifiedMapWithHashingStrategy
.
<Primitive>Iterable.each()
Behaves exactly same as <Primitive>Iterable.forEach()
. Added to be in sync with RichIterable.each(Procedure)
that was introduced in 6.0 to avoid ambiguity conflict with Iterable.forEach(Consumer)
.
Lazy<Primitive>Iterable.collect<Primitive>()
aggregateInPlaceBy()
, aggregateBy()
, zip()
, zipWithIndex()
, partition()
, selectInstancesOf()
, collectIf()
, groupBy()
, and groupByEach()
on MutablePrimitiveObjectMap
Use the Kahan summation algorithm on sum()
and sumBy()
methods on primitive collections
Other new Functionality
CharAdapter
, CodePointAdapter
and CodePointList
CharAdapter
implementsCharSequence
andImmutableCharList
, and it represents String as a collection of char values.CharPointAdapter
implementsCharSequence
andImmutableIntList
. It behaves similarly toCharAdapter
but it represents String as the unicode codepoint values that are ints.CharPointList
is similar toCharPointAdapter
but it calculates and caches the unicode code point values as an ImmutableIntList internally.
CharAdapter chars = CharAdapter.adapt("This is an example");
CodePointAdapter codePoints = CodePointAdapter.adapt("Can you read this Kanji \"\uD840\uDC00\"? I cannot.");
CodePointList codePointList = CodePointList.from("BMP stands for Basic Multilingual Pane. \"\uD840\uDC00\" is a unicode character outside BMP.");
System.out.println("Upper case: " + chars.collectChar(Character::toUpperCase));
System.out.println("Unicode character outside Basic Multilingual Pane: " + codePoints.reject(Character::isBmpCodePoint).distinct());
System.out.println("English only: " + codePointList.reject(Character::isIdeographic));
Prints
Upper case: THIS IS AN EXAMPLE
Unicode character outside Basic Multilingual Pane: 𠀀
English only: BMP stands for Basic Multilingual Pane. "" is a unicode character outside BMP.
ImmutableSortedBag
ListIterable.distinct(HashingStrategy)
Returns a new ListIterable
containing the distinct elements in this list. Conceptually similar to new UnifiedSetWithHashingStrategy(hashingStrategy, listIterable).toList()
but retains the original order.
MutableBagMultimap.putOccurrences(K key, V value, int occurrences)
Adds occurrences
of value
to the MutableBag
at key
in the multimap.
MutableList.shuffleThis(): MutableList
Shuffles this list and returns this list. Overload optionally takes a Random
.
Predicates.cast()
and Functions.cast()
Allows a Java 8 lambda or method reference to be used in a method taking a predicate or a function without requiring a cast. The methods can be used in places where two or more method overloads could apply when used with a lambda or method reference.
Lists.mutable.of(1, 2, null).removeIf(each -> each == null);
This code fails to compile with the following error.
Error: java: reference to removeIf is ambiguous
both method removeIf(java.util.function.Predicate<? super E>) in java.util.Collection and method removeIf(com.gs.collections.api.block.predicate.Predicate<? super T>) in com.gs.collections.api.collection.MutableCollection match
You can work around the problem by using a cast or the method Predicates.cast()
.
Lists.mutable.of(1, 2, null).removeIf(Predicates.cast(each -> each == null));
Add factory method for creating mutable sets and maps of a given initial capacity.
For example: Sets.mutable.withInitialCapacity(100)
Optimizations and Performance Tests
- Optimize
FastList.addAll()
andUnifiedSet.addAll()
forRandomAccess
lists. - Optimize
UnifiedMap
's short-circuit methods to not delegate to an iterator. - Refactor
ImmutableSortedBag.newWith()
andnewWithout()
to take O(n) time. - Add JDK 8 Streams based JMH tests for
FastList
. - Add JMH Tests for
HashMap<Integer, Integer>
Bug Fixes
- Fix bug in
CollectIterable.toArray()
where it returnsT[]
instead ofObject[]
. - Fix iterator's
remove()
method inObjectPrimitiveHashMap
so that it doesn't rehash. - Fix code point iteration in
StringIterate
and provideCharAdapter
andCodePointList
as OO alternatives for string iteration.
Documentation and Deprecation
- Add information about required Java versions to
README.md
. Fixes #18. - Enhance Javadoc of
Iterate
. - Update Javadoc in
InternalIterable
andRichIterable
to include Java 8 lambda examples. - Deprecate
ArrayIterate.sort()
and recommend direct calls toArrays.sort()
. - Deprecate overloaded methods in
StringIterate
and add specialization alternatives that work better with Java 8 lambdas.
6.2.0 (June 2015)
Binaries
Javadoc
Acquiring GS Collections
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>6.2.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>6.2.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>6.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>6.2.0</version>
</dependency>
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="6.2.0" />
<dependency org="com.goldmansachs" name="gs-collections" rev="6.2.0" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="6.2.0" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="6.2.0"/>
Optimizations
- Improve primitive map performance.
- Optimize addAll/removeAll on HashBag when a Bag is passed as the parameter.
Bug Fixes
- Fix bug in remove() in HashBag's iterator.
- Fix bug in remove() in HashBag and TreeBag's iterators.
6.1.0 (March 2015)
Binaries
Javadoc
JDiff
Differences between 6.0.0 and 6.1.0
Acquiring GS Collections
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>6.1.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>6.1.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>6.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>6.1.0</version>
</dependency>
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="6.1.0" />
<dependency org="com.goldmansachs" name="gs-collections" rev="6.1.0" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="6.1.0" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="6.1.0"/>
New Functionality
Travis CI build
A continuous build runs at travis-ci and its status is reflected in the README badge.
Allow ArrayList to have subclasses.
Fixes #19.
ParallelIterable.flatCollect()
Optimizations
- Optimize ArrayList.addAll(PrimitiveIterable) to avoid an array copy when the parameter is also a ArrayList. Fixes #19.
- Optimize primitive maps/sets probing method.
Bug Fixes
- Fix size() on the views of ConcurrentHashMap.
- Fix the iteration order of several iteration patterns.
Performance and memory tests
Many new performance and memory tests supporting the material in the presentation "Scala Collections Performance" at Scala Days San Francisco 2015. There are new JMH tests for several lists, sorted sets, and maps as well as new memory tests for several sets and maps.
6.0.0 (February 2015)
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 of RichIterable.forEach(Procedure)
. Consumer
and Procedure
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 using RichIterable.each(Procedure)
which behaves exactly like InternalIterable.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 the RichIterable
. Similar to RichIterable.forEach(Procedure)
and RichIterable.each(Procedure)
but returns this
.
LazyIterable.tap(Procedure): LazyIterable
LazyIterable.tap(Procedure)
overrides RichIterable.tap(Procedure)
and executes lazily. It is useful to "tap into" a method chain, executing a Procedure
on every element of the LazyIterable
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 a MutableSortedBag
implementation and sorts it using the natural order of the elements. RichIterable.toSortedBag(Comparator)
sorts using the Comparator
parameter. RichIterable.toSortedBagBy(Function)
sorts based on the natural order of the attribute returned by the Function
parameter.
RichIterable.groupByUniqueKey(Function): MapIterable.
Similar to RichIterable.groupBy(Function)
. The keys returned by the Function
must be unique, otherwise an exception is thrown. Since the keys are unique, groupByUniqueKey()
returns a MapIterable
instead of a Multimap
.
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 groupBy Function
. Each group is converted to numbers using the primitive function and then summed. sumByInt()
and sumByLong()
return ObjectLongMap
. sumByFloat()
and sumByDouble()
return ObjectDoubleMap
.
OrderedIterable API
OrderedIterable interface for order dependent functionality.
An OrderedIterable
is a RichIterable
with some meaningful order, such as insertion order, access order, or sorted order. ReversibleIterable
and SortedIterable
now extend OrderedIterable
.
Several methods were pulled up to OrderedIterable
.
indexOf(Object)
takeWhile(Predicate)
,dropWhile(Predicate)
, andpartitionWhile(Predicate)
distinct()
toStack()
Other methods on InternalIterable
and RichIterable
are now deprecated because they imply a meaningful order which not all containers have. These methods are overridden on OrderedIterable
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 returns true
for all elements e1 of the current OrderedIterable
and e2 of the other OrderedIterable
.
The predicate is evaluated for pairs of elements at the same position in both OrderedIterable
s. The corresponds()
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. The detectIndex()
method short circuits as soon as it finds an element which satisfies the Predicate
.
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. The detectLastIndex()
method iterates in reverse order and short circuits as soon as it finds an element which satisfies the Predicate
.
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 if n
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 if n
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 to FastList
and UnifiedSet
. 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(...
5.1.0 (June 2014)
Binaries
Javadoc
JDiff
Differences between 5.0.0 and 5.1.0
Acquiring GS Collections
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>5.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>5.1.0</version>
</dependency>
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="5.1.0" />
<dependency org="com.goldmansachs" name="gs-collections" rev="5.1.0" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="5.1.0" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="5.1.0"/>
Improvements
Java Microbenchmark Harness performance test suite
There are two new modules named jmh-scala-tests
and jmh-tests
which include new performance tests leveraging Java Microbenchmark Harness. They supplement the existing performance-tests
module. The focus of these tests is to compare the performance of various iteration patterns across several libraries, including GS Collections, Java 8 Streams, Scala collections, and Guava. Each iteration pattern is tested in serial and in parallel. Where the API is available, they are also tested eagerly and lazily.
As an example, here is the test of the GS Collections implementation of count()
, using serial eager evaluation.
@GenerateMicroBenchmark
public void serial_eager_gsc()
{
int evens = this.integersGSC.count(each -> each % 2 == 0);
Assert.assertEquals(SIZE / 2, evens);
}
Use of lambdas in the test suites
The GS Collections library is compiled with Java 5 to ensure its backwards compatibility. However, the test modules are free to use any version of Java. Most of the test modules now use Java 8. We've replaced all of the anonymous inner classes with lambdas or method references. We've also replaced many usages of code block factories with the equivalent lambda or method reference. For example, instead of using Functions.getToString()
, we use String::valueOf
in most tests.
5.0.0 (March 2014)
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 through LazyIterable
, the view returned by RichIterable.asLazy()
. GS Collections 5.0 adds parallel-lazy evaluation through ParallelIterable
, the view returned by asParallel(ExecutorService, int batchSize)
. The method asParallel
is not on interfaces like RichIterable
yet, but rather on a few supported collections, including FastList
and UnifiedSet
.
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 evaluation
ParallelListIterable<String> evenStrings = evenNumbers.collect(Object::toString); // deferred evaluation
MutableList<String> strings = evenStrings.toList(); // forced evaluation
threadPool.shutdown();
Assert.assertEquals(FastList.newListWith("2", "4", "6", "8"), strings);
The calls to select
and collect
are lazy, indicated by the fact that they return subclasses of ParallelIterable
. The call to toList()
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 to asParallel.
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
, and detectWithIfNone
on RichIterable
These are the two-argument forms of anySatisfy
, allSatisfy
, noneSatisfy
, count
, partition
, detect
and detectIfNone
. They take a Predicate2
instead of a Predicate
, and a second argument, which is passed as the second argument to the Predicate2
. 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 on MutableCollection
and were pulled up to RichIterable
. Here is a comparison between anySatisfy
and anySatisfyWith
.
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 to collect<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 on MutableCollection
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)
and ListIterable.binarySearch(T, Comparator)
Similar to java.util.Collections.binarySearch
, but available from the object-oriented API.
LazyIterable.distinct()
and LazyIterate.distinct(Iterable)
Similar to toSet(),
but returns a LazyIterable
(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 a Multimap
instead of a MapIterable
. Since the keys in the MapIterable
are unique, flip()
returns a SetMultimap
instead of the more general Multimap
interface. In summary, MapIterable<K, V>.flip()
returns SetMultimap<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 the MapIterable
are unique and thus returns MapIterable
instead of Multimap
. Throws IllegalArgumentException
if the MapIterable
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 to getIfAbsentPut(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")); // mutates
Assert.assertEquals("3", map.getIfAbsentPut(3, "5")); // does not mutate
Verify.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 to put(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 to setOccurrences()
.
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 the ObjectIntProcedure
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()
and keyValuesView()
on primitive maps
Returns a lazy view of keys or key/value pairs respectively.
keySet()
and values()
on synchronized, unmodifiable, and immutable primitive maps
These methods already existed on the API but threw UnsupportedOperationException
s in places....
4.2.0 (October 2013)
Acquiring GS Collections
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>4.2.0</version>
</dependency>
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="4.2.0" />
<dependency org="com.goldmansachs" name="gs-collections" rev="4.2.0" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="4.2.0" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="4.2.0"/>
New Functionality
SortedBag
SortedBag
has all of the same properties as a Bag
, and additionally maintains order by a Comparator
or by the elements' natural order.
The main implementation is TreeBag
which delegates to a TreeSortedMap
to store its data.
MutableSortedBag<Integer> emptySortedBag = TreeBag.newBag();
MutableSortedBag<Integer> emptySortedBagWithComparator =
TreeBag.newBag(Collections.reverseOrder());
MutableSortedBag<Integer> naturalOrder =
TreeBag.newBagWith(1, 2, 3);
MutableSortedBag<Integer> reversedOrder =
TreeBag.newBagWith(Collections.reverseOrder(), 4, 3, 3, 2, 2, 1);
MutableSortedBag<Integer> sortedBagFromFastList =
TreeBag.newBag(FastList.newListWith(1, 2, 3));
MutableSortedBag<Integer> sortedBagFromFastListWithComparator =
TreeBag.newBag(Collections.reverseOrder(), FastList.newListWith(1, 2, 3));
BiMap
BiMap
is a map that allows users to perform lookups from both directions. Both the keys and the values in a BiMap are unique.
The main implementation is HashBiMap
.
inverse()
BiMap.inverse()
returns a view where the position of the key type and value type are swapped.
MutableBiMap<Integer, String> biMap =
HashBiMap.newWithKeysValues(1, "1", 2, "2", 3, "3");
MutableBiMap<String, Integer> inverse = biMap.inverse();
Assert.assertEquals("1", biMap.get(1));
Assert.assertEquals(Integer.valueOf(1), inverse.get("1"));
Assert.assertTrue(inverse.containsKey("3"));
Assert.assertEquals(Integer.valueOf(2), inverse.put("2", 4));
put()
MutableBiMap.put()
behaves like Map.put()
on a regular map, except it throws when a duplicate value is added.
MutableBiMap<Integer, String> biMap = HashBiMap.newMap();
biMap.put(1, "1"); // behaves like a regular put()
biMap.put(1, "1"); // no effect
biMap.put(2, "1"); // throws IllegalArgumentException
forcePut()
This behaves like MutableBiMap.put()
, but it silently removes the map entry with the same value before putting the key-value pair in the map.
MutableBiMap<Integer, String> biMap = HashBiMap.newMap();
biMap.forcePut(1, "1"); // behaves like a regular put()
biMap.forcePut(1, "1"); // no effect
biMap.put(1, "2"); // replaces the [1,"1"] pair with [1, "2"]
biMap.forcePut(2, "2"); // removes the [1, "2"] pair before putting
Assert.assertFalse(biMap.containsKey(1));
Assert.assertEquals(HashBiMap.newWithKeysValues(2, "2"), biMap);
Optimize HashBag by delegating to ObjectIntHashMap
HashBag
now delegates to ObjectIntHashMap<K>
instead of a MutableMap<K, Counter>
. This saves memory by eliminating the Counter
wrapper objects.
Functions.chain()
The Functions.chain<primitive>()
methods are similar to Functions.chain()
, but they take a primitive function as the second argument. There are variants for all eight primitives:
- chainBoolean()
- chainByte()
- chainChar()
- chainDouble()
- chainInt()
- chainFloat()
- chainLong()
- chainShort()
4.1.0 (September 2013)
Acquiring GS Collections
Maven
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-api</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-testutils</artifactId>
<version>4.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.goldmansachs</groupId>
<artifactId>gs-collections-forkjoin</artifactId>
<version>4.1.0</version>
</dependency>
Ivy
<dependency org="com.goldmansachs" name="gs-collections-api" rev="4.1.0" />
<dependency org="com.goldmansachs" name="gs-collections" rev="4.1.0" />
<dependency org="com.goldmansachs" name="gs-collections-testutils" rev="4.1.0" />
<dependency org="com.goldmansachs" name="gs-collections-forkjoin" rev="4.1.0"/>
New Functionality
Version 4.1 has been released to support deployment to Maven Central. Most of the changes are build related. There is only one piece of new functionality.
Comparators.byFunction
The Comparators.by<primitive>Function()
methods are just like Comparators.byFunction()
, but specialized for primitive types. They allow you to sort or compare elements by some primitive attribute without doing any autoboxing.