7.0.3 (February 2016)

@itohro itohro released this Mar 16, 2016 · 1 commit to master since this release

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"/>
  • Feb 19, 2016

    7.0.2

    [GSCOLLECT-1672] Add assertions for map inequality.
    git-svn-id: svn+ssh://gscollections.svn.services.gs.com/svnroot/gscollections-svn/trunk@930 d5c9223b-1aff-41ac-aadd-f810b4a99ac4

7.0.1 (December 2015)

@itohro itohro released this Mar 16, 2016 · 13 commits to master since this release

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)

@goldmansachs goldmansachs released this Nov 4, 2015 · 17 commits to master since this release

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 returns boolean.
  • Sorted sets, bags, and maps implement ReversibleIterable. Added OrderedMap interface to represent a linked hash map.
  • Overrode BiMap.partition() to return PartitionUnsortedSet.
  • UnifiedMap and UnifiedSet now throw if constructed with a load factor greater than 1.
  • toStringOfItemToCount() in ImmutableEmptyBag 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 implements CharSequence and ImmutableCharList, and it represents String as a collection of char values.
  • CharPointAdapter implements CharSequence and ImmutableIntList. It behaves similarly to CharAdapter but it represents String as the unicode codepoint values that are ints.
  • CharPointList is similar to CharPointAdapter 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() and UnifiedSet.addAll() for RandomAccess lists.
  • Optimize UnifiedMap's short-circuit methods to not delegate to an iterator.
  • Refactor ImmutableSortedBag.newWith() and newWithout() 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 returns T[] instead of Object[].
  • Fix iterator's remove() method in ObjectPrimitiveHashMap so that it doesn't rehash.
  • Fix code point iteration in StringIterate and provide CharAdapter and CodePointList 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 and RichIterable to include Java 8 lambda examples.
  • Deprecate ArrayIterate.sort() and recommend direct calls to Arrays.sort().
  • Deprecate overloaded methods in StringIterate and add specialization alternatives that work better with Java 8 lambdas.

6.2.0 (June 2015)

@goldmansachs goldmansachs released this Jun 9, 2015 · 68 commits to master since this release

Binaries

gs-collections-6.2.0.zip

Javadoc

6.2.0 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)

@goldmansachs goldmansachs released this Mar 25, 2015 · 89 commits to master since this release

Binaries

gs-collections-6.1.0.zip

Javadoc

6.1.0 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)

@goldmansachs goldmansachs released this Feb 9, 2015 · 115 commits to master since this release

Binaries

gs-collections-6.0.0.zip

Javadoc

6.0.0 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), and partitionWhile(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() and getLast()
  • forEach(startIndex, endIndex, procedure)
  • forEachWithIndex(ObjectIntProcedure)
  • forEachWithIndex(fromIndex, toIndex, objectIntProcedure)

OrderedIterable.corresponds(OrderedIterable, Predicate2).

Returns true if both OrderedIterables 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 OrderedIterables. 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() 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 takes Pair<K, V> instead.

Multimap.forEachKeyMultiValues(Procedure2<K, ? super Iterable>)

Similar to forEachKeyValue(Procedure2<K, V>) but the Procedure2 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() and RichIterable.reject() but the Predicate2 is evaluated against each key/value pair. The implementation of the Predicate2 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() and Multimap.rejectKeysValues() but the Predicate2 takes (K, Iterable) pairs instead of (K, V) pairs.

Multimap.collectKeysValues(Function2<? super K, ? super V, Pair<K2, V2>>).

Similar to RichIterable.collect() but the Function2 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 using Multimap.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, and MutableBiMap now extend a common interface MutableMapIterable. ImmutableMap, ImmutableSortedMap, and ImmutableBiMap now extend a common interface ImmutableMapIterable. The SetIterable and Bag hierarchy had similar changes.

MutableIterator.remove()

Mutable<Primitive>Iterator is a new subclass of <Primitive>Iterator that adds the remove() method. It behaves similarly to Iterator.remove(), but does not appear on immutable primitive containers and thus doesn't throw UnsupportedOperationException. 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 an ImmutableList.

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 a Pair. 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 for Strings rather than collections.

New Containers

ImmutableBiMap

ImmutableBiMaps can be created by using the BiMaps factory or by calling MutableBiMap.toImmutable().

MutableBiMap<Integer, Character> biMap = ...;
ImmutableBiMap<Integer, Character> characters = biMap.toImmutable();

MultiReaderFastListMultimap, MultiReaderUnifiedSetMultimap, and MultiReaderHashBagMultimap.

Thread-safe Multimaps backed by ConcurrentMutableMaps of multi-reader collections.

Tests

JUnit Runner for interfaces containing concrete tests. New test suite leveraging virtual extension methods.

A new JUnit Runner named Java8Runner 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:

@Test
default 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 a MutableCollection and a ListIterable. Any assertions about MutableCollections and ListIterables should be true for MutableLists as well. Thus, the test interface MutableListTestCase extends both MutableCollectionTestCase and ListIterableTestCase.

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, and sumBy.

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 and LongIntMapTest.

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.

5.1.0 (June 2014)

@goldmansachs goldmansachs released this Jun 2, 2014 · 297 commits to master since this release

Binaries

gs-collections-5.1.0.zip

Javadoc

5.1.0 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)

@goldmansachs goldmansachs released this Mar 21, 2014 · 334 commits to master since this release

Binaries

gs-collections-5.0.0.zip

Javadoc

5.0.0 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 MutableCollections. 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 Pairs, 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 UnsupportedOperationExceptions 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 or Object).

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 on MutableObject<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 the valueOf() method of the delegate Function only if the parameter is not null, otherwise it returns null or the provided null 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 two Integers 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-generated hashCode() methods. It start with the first delegate strategy's computed hashcode, and then repeatedly multiplies the accumulated hashcode by 31 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 of equals, and System.identityHashCode in the implementation of computeHashCode.

HashingStrategies.fromFunctions(Function, Function) and HashingStrategies.fromFunctions(Function, Function, Function)

Creates a HashingStrategy from each Function, 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 to equals and computeHashCode do not create any garbage.

ReversibleIterable and SortedIterable Interfaces

Two 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 like asReversed() and reverseForEach(). Lists are the most common ReversibleIterables, and ListIterable extends ReversibleIterable.

ReversibleIterable Inheritance Hierarchy

SortedIterable, is an ordered iterable where the elements are stored in sorted order. Its method comparator() returns the Comparator used to sort the elements, or null if they are sorted in natural order. SortedSetIterable and SortedBag extend SortedIterable.

Changes in the Bag Interface Hierarchy

The inheritance hierarchy of Bags is now more consistent with Sets. We introduced a new interface UnsortedBag, as a sibling of SortedBag. Bag no longer overrides collect, so it returns RichIterable instead of Bag. SortedBag.collect returns ListIterable instead of Bag. UnsortedBag.collect returns UnsortedBag, which means the implementations of UnsortedBag.collect are unchanged. The new interface structure is as follows:

Bag Inheritance Hierarchy

The change to the interface hierarchy changed the serialized forms of TreeBag and UnmodifiableSortedBag.

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 from SynchronizedMutableCollection, and all the classes that used to extend SynchronizedMutableCollection like SynchronizedMutableList and SynchronizedMutableSet now extend AbstractSynchronizedMutableCollection directly. Similar changes have been made to the unmodifiable collections.

Serialized form of immutable collections

The serialized forms of ImmutableSet, ImmutableBag and ImmutableMap implementations have been changed.

The ImmutableSet implementations now use a proxy class for serialization.

The implementations of ImmutableMap and ImmutableBag already used proxy classes for serialization. These proxy classes were inner classes inside AbstractImmutableMap and AbstractImmutableBag respectively. These proxy classes were moved to top level, package private classes.

4.2.0 (October 2013)

@goldmansachs goldmansachs released this Oct 28, 2013 · 489 commits to master since this release

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