GS Collections Reference Guide
Transcript of GS Collections Reference Guide
GS Collections
User Reference Guide
Copyright © 2014 Goldman Sachs. All Rights Reserved.
Version 5.0.0 (2014/03/21)
Contact: [email protected]
GS Collections
GS Collections | TOC
3
Contents
About GS Collections......................................................................................................................5Getting Started With GS Collections............................................................................................7
Chapter 1: Iteration patterns.................................................................................. 9Common iteration patterns................................................................................................................................. 10
Select/Reject pattern............................................................................................................................... 10Collect pattern.........................................................................................................................................13Short-circuit patterns...............................................................................................................................15ForEach pattern.......................................................................................................................................18InjectInto pattern.....................................................................................................................................19
RichIterable......................................................................................................................................................... 20Lazy iteration.......................................................................................................................................... 21Parallel-lazy iteration.............................................................................................................................. 22RichIterable methods.............................................................................................................................. 23
Map iteration methods........................................................................................................................................31Creating iterable views of maps.............................................................................................................31Collecting entries.................................................................................................................................... 31Finding, testing and putting values........................................................................................................ 32Flipping maps......................................................................................................................................... 33
Chapter 2: Collections and containers................................................................. 35Basic collection types......................................................................................................................................... 36
ListIterable...............................................................................................................................................36SetIterable................................................................................................................................................39MapIterable............................................................................................................................................. 39Bag...........................................................................................................................................................41StackIterable............................................................................................................................................42Multimap................................................................................................................................................. 43
Primitive collections........................................................................................................................................... 44Creating and converting collections...................................................................................................................46Protecting collections..........................................................................................................................................46
Immutable collections.............................................................................................................................47Protective wrappers.................................................................................................................................48
Chapter 3: Code blocks......................................................................................... 51Predicate.............................................................................................................................................................. 53Function...............................................................................................................................................................53Procedure.............................................................................................................................................................55
Appendix A: Help...................................................................................................57Verify...................................................................................................................................................................58Q & A................................................................................................................................................................. 58GS Collections Cheat Sheet............................................................................................................................... 59
GS Collections | TOC
4
5
About GS Collections
A collections framework for Java based on Smalltalk patterns.
GS Collections is a library of collection-management utilities that work with the Java Collections Framework (JCF).GS Collections offers JCF-compatible implementation alternatives for List, Set and Map. It also introduces a host ofnew features including Multimaps and Bags, lazy evaluation, immutable containers, and parallel iteration utility.
GS Collections leverages the idea of internal iteration—putting collection-handling methods on the collectionclasses, a concept derived from the Smalltalk language. Internal iteration affords a more consistent and intuitiveapproach to using collections by encapsulating the details of how various iteration patterns are implemented. Hidingthis complexity lets you write more readable code with less duplication.
About this guide
This Guide is an introduction to basic GS Collections concepts and its commonly-used features. It provides a high-level survey of the GS Collections library and its capabilities. The topics covered are:
• Iteration patterns: the logic underlying GS Collections methods.• Collections & containers: the JCF compatible collection types and new containers introduced in GS Collections.• Code blocks: a function that can be passed around as data.• Utilities: factory classes, static methods, and other features of the library.
GS Collections | About GS Collections
6
Typographical conventions
interface class method code block interface code block implementation
7
Getting Started With GS Collections
It is recommended that first time users go through the GSC Kata. The Kata is a fun way to help you learn idiomaticGS Collections usage through coding exercises. The Kata can be found on our GitHub page: https://github.com/goldmansachs/gs-collections-kata. To run the Kata, please refer to the setup instructions found on page 24 of the Katadocument.
The Kata can be found on our GitHub page: https://github.com/goldmansachs/gs-collections-kata. To install the Kata,please refer to the Kata PDF setup instructions found on page 25 of the slideshow.
GS Collections | Getting Started With GS Collections
8
9
Chapter
1Iteration patterns
Topics:
• Common iteration patterns• RichIterable• Map iteration methods
GS Collections extends the Java Collections Framework with new interfacesand classes and provides additional methods. These new methods implementiteration patterns derived from the collection protocol of the Smalltalklanguage (e.g., select, reject, collect, detect).
In idiomatic Java, iteration is performed by external for and while loopsthat enclose a block of business logic to be performed on each element of acollection. This is an approach that often leads to much duplication of codestructure.
In GS Collections, business logic is reified as a code block: a class that ispassed as a parameter to an iteration method. Each implementation of aniteration method iterates over the collection, passing each element to the codeblock for processing.
The most important advantage of internal iteration patterns is that theyincrease readability by giving names to the structural iteration patterns andby reducing code duplication. Moreover, by encapsulating implementationwithin specialized collection types (e.g., list, sets, maps), iteration can beoptimized for the particular type.
GS Collections | Iteration patterns
10
Common iteration patternsThe most commonly-used iteration patterns in GS Collections are:
• Filtering patterns:
• Select• Reject• Partition
• Transforming patterns:
• Collect• Flatten• GroupBy
• "Short-circuit" patterns:
• Detect• AnySatisfy• AllSatisfy
• Generic action patterns:
• ForEach• InjectInto
Select/Reject patternFilter a collection to create a new collection: includes select, reject, and
partition.
Methods using the Select pattern return a new collection comprising those elements from the source collection thatsatisfy some logical condition. Reject is the inverse pattern, returning a new collection of elements that do not satisfythe condition. The condition is a boolean expression in the form of single-argument code block that implements thePredicate interface.
Select pattern examples:
Pseudocode create <newCollection> for each <element> of <collection> if condition(<element>) add <element> to <newCollection>
JDK List<Integer> greaterThanFifty = new ArrayList<Integer>();for (Integer each : list){ if (each.intValue() > 50) { greaterThanFifty.add(each); }}
GS Collections | Iteration patterns
11
Select, using an anonymous inner class as a code block:
GSC (Java 5+) MutableList<Integer> greaterThanFifty = list.select(new Predicate<Integer>() { public boolean accept(Integer each) { return each > 50; } });
Here, a Predicate is created using the Predicates factory:
GSC (Java 5+) list.select(Predicates.greaterThan(50));
GSC (Java 8) List<Integer> greaterThanFifty = list.select(each -> each > 50);
Reject pattern examples:
Pseudocode create <newCollection> for each <element> of <collection> if not condition(<element>) add <element> to <newCollection>
JDK List<Integer> notGreaterThanFifty = new ArrayList<Integer>();for (Integer each : list){ if (each <= 50) { notGreaterThanFifty.add(each); }}
GSC (Java 5+) list.reject(Predicates.greaterThan(50));
GSC (Java 8) List<Integer> notGreaterThanFifty = list.reject(each -> each > 50);
Select and Reject methods
These GS Collections methods implement the Select and Reject pattern:
select(Predicate) : RichIterable
reject(Predicate) : RichIterable
The Predicate is evaluated for each element of the collection. The selected elements are those where the Predicatereturned true (false for rejected). The selected (or rejected) elements are returned in a new collection of the sametype.
select(Predicate, targetCollection) : targetCollection
reject(Predicate, targetCollection) : targetCollection
Same as the select/reject methods with one argument, but results are added to the specified targetCollection.
selectWith(Predicate2, argument) : RichIterable
rejectWith(Predicate2, argument) : RichIterable
For each element of the collection, Predicate2 is evaluated with the element as one argument, plus one additionalargument; selected or rejected elements are returned in a new collection of the same type. See Reusing a code blockfor more information.
GS Collections | Iteration patterns
12
selectWith(Predicate2, argument, targetCollection) : targetCollection
rejectWith(Predicate2, argument, targetCollection) : targetCollection
Same as the selectWith/rejectWith methods, but results are added to the specified targetCollection.
Partition patternCreate two collections using Select and Reject.
The Partition pattern allocates each element of a collection into one of two new collections depending on whether theelement satisfies the condition expressed by the Predicate. In effect, it combines the Select and Reject patterns. Thecollections are returned in a PartitionIterable specialized for the type of the source collection. You can retrieve theselected and rejected elements from the PartitionIterable. In this example, the list of people is partitioned into lists ofadults and children.
GSC (Java 5+) MutableList<Person> people =...PartitionMutableList<Person> partitionedFolks = people.partition( new Predicate<Person>() { public boolean accept(Person each) { return each.getAge() >= 18; } });MutableList<Person> adults = partitionedFolks.getSelected();MutableList<Person> children = partitionedFolks.getRejected();
GSC (Java 8) PartitionMutableList<Person> partitionedFolks = people.partition(person -> person.getAge() >= 18);
MutableList<Person> adults = partitionedFolks.getSelected();MutableList<Person> children = partitionedFolks.getRejected();
Partitioning methods
These GS Collections methods implement the partition pattern:
partition(Predicate) : PartitionIterable
Returns a PartitionIterable, a logical pair of containers. The first container consists of all elements that satisfythe Predicate. The second container consists of all elements that do not satisfy the Predicate. The subtypes ofPartitionIterable correspond with the subtypes of RichIterable.
partitionWith(Predicate2, argument) : PartitionIterable
For each element of the collection, Predicate2 is evaluated with the element as one argument, plus one additionalargument; partitioned elements are returned in a new collection of type PartitionIterable.
GS Collections | Iteration patterns
13
Collect patternTransform a collection's elements, creating a new collection: includes
collect, flatCollect, and groupBy.
The Collect pattern methods return a new collection whose data elements are the results of an evaluation performedby the code block; that is, each element of the original collection is mapped to a new object, which is usually adifferent type. The code block used as the collect method's parameter implements the Function interface.
Pseudocode create <newCollection> for each <element> of <collection> <result> = transform(<element>) add <result> to <newCollection>
JDK List<Address> addresses = new ArrayList<Address>();
for (Person person : people){ addresses.add(person.getAddress());}
GSC (Java 5+) MutableList<Person> people =...;
Function<Person, Address> addressFunction = new Function<Person, Address>() { public Address valueOf(Person person) { return person.getAddress(); } };
MutableList<Address> addresses = people.collect(addressFunction);
Notice that this assumes each person in the people collection has just one address. If, instead, a person has multipleaddresses, the Function returns a list of addresses for each person (a list that has only one element if the person hasjust one address); the result is a List of Lists:
GSC (Java 5+) MutableList<Person> people =...;
Function<Person, MutableList<Address>> addressFunction = new Function<Person, MutableList<Address>>() { public MutableList<Address> valueOf(Person person) { return person.getAddresses(); } };MutableList<MutableList<Address>> addresses = people.collect(addressFunction);
GSC (Java 8) MutableList<MutableList<Address>> addresses = people.collect(person -> person.getAddresses());
//orMutableList<MutableList<Address>> addresses = people.collect(Person::getAddresses);
Other Collect-style patterns
GS Collections provides two specialized variations on the Collect pattern: Flatten and GroupBy. Like Collect, bothmethods take a single Function as a parameter.
Collect methods
These GS Collections methods implement the Collect pattern:
GS Collections | Iteration patterns
14
collect(Function) : RichIterable
For each element of the collection, the Function is evaluated with the current element as the argument; returns anew collection of the same size and the transformed type.
collectInt(IntFunction) : IntIterable
Similar to collect, but it takes an IntFunction and returns a primitive collection. There are variants for all eightprimitives: collectBoolean, collectFloat etc.
collect(Function, targetCollection) : targetCollection
Same as collect, except that the results are added to the specified targetCollection.
collectInt(IntFunction, targetCollection) : targetCollection
Same as collectInt, except that the results are added to the specified targetCollection. There are variants for all eightprimitives.
collectIf(Predicate, Function) : RichIterable
Same as collect, except that the Predicate is first evaluated with the element as the argument to filter the collection.
collectIf(Predicate, Function,targetCollection) : targetCollection
Same as collectIf, except that the results are added to the specified targetCollection.
collectWith(Predicate2, argument2) : RichIterable
Same as collect, but the Predicate2 is evaluated with the element as one argument, plus one additional argument;returns a new collection of the same size and the transformed type.
collectWith(Predicate2, argument2,targetCollection) : targetCollection
Same as collectWith, except that the results are added to a specified targetCollection. (On all RichIterables sinceversion 1.0)
Flatten patternCreate a single, linear collection from selected values of a collection's
elements.
The Flatten pattern is a specialized form of the the Collect pattern. It returns a single-level, or "flattened," collectionof attribute values from a source collection's elements.
flatCollect(Function) : RichIterable
Applies the Function to each element. The Function must return an Iterable type. Returns the intermediate Iterablesin a single, flattened collection.
GS Collections | Iteration patterns
15
Given a list of people (as in the collect method example), here is how flatCollect could be used to create a flat listfrom the address fields of the person objects in that list, using the same Function (addressFunction):
Pseudocode create <newCollection> for each <element> of <collection> <results> = transform(<element>) Add all <results> to <newCollection>
JDK List<Address> addresses = new ArrayList<Address>();for (Person person : people){ addresses.addAll(person.getAddresses());}
GSC (Java 5+) MutableList<Address> addresses = people.flatCollect(addressFunction);
Note the flatCollect method's similarity to a collect method having the same signature: each method's Functionparameter maps to an Iterable type. This is optional for collect, but required of flatCollect. Both methods return anew collection. The difference is that collect in this form creates a collection of collections from a simple List, Set orBag, while flatCollect performs a different (and in this instance, somewhat more useful) action, returning a flat list ofaddresses.
GSC (Java 8) MutableList<Address> flatAddress = people.flatCollect(person -> person.getAddress());MutableList<Address> flatAddress = people.flatCollect(Person::getAddress);
GroupBy patternCreate a Multimap from a collection by grouping on a selected or
generated key value.
The GroupBy pattern gathers the elements on the collection into a map-like container called a Multimap, whichassociates multiple values for each key. The Function is applied to each element and the result is used as the key intothe Multimap where the element should appear as the value.
groupBy(Function) : Multimap
Group the elements into a new Multimap; uses the Function to get the key for each element.
groupBy(Function, targetMultimap) : targetMultimap
Same as groupBy except that results are added to the specified targetMultimap.
groupByEach(Function) : Multimap
Same as groupBy except that the Function transforms each value into multiple keys, returning a new Multimapcontaining all the key/value pairs.
Short-circuit patternsMethods that control processing by testing a collection for a logical
condition: includes detect, anySatisfy, and allSatisfy.
The "short-circuit" patterns - Detect, AnySatisfy and AllSatisfy - are so called because they describe methods thatcease execution when a specific condition is met. With each iteration, the Predicate is evaluated. If the evaluationresolves as a specified boolean (true/false) value, then iteration halts and returns the appropriate value.
GS Collections | Iteration patterns
16
Detect patternFinds and returns the first element that satisfies a given logical
expression.
Detect returns the first element that satisfies a Predicate. If every element in the collection is tested and the Predicatenever returns true, then the method returns null.
Pseudocode for each <element> of <collection> if condition(<element>) return <element>
JDK for (int i = 0; i < list.size(); i++){ Integer v = list.get(i); if (v.intValue() > 50) { return v; } return null;}
GSC (Java 5+) list.detect(Predicates.greaterThan(50));
GSC (Java 8) list.detect(each -> each > 50);
Detect methods
detect(Predicate) : element
Return the first element which satisfies the Predicate or null if no element satisfies the Predicate.
detectIfNone(Predicate, Function0) : element (or Function0 result)
Same as detect, but if no element causes Predicate to evaluate as true, return the result of evaluating Function0.
detectWith(Predicate2, parameter) : element
Returns the first element that evaluates as true for the specified Predicate2 and parameter, or null if none evaluateas true. See Reusing a code block for more information.
detectWithIfNone(Predicate2, parameter, Function0) : element (or Function0 result)
Same as detectWith, but if no element causes Predicate2 to evaluate as true, return the result of evaluatingFunction0.
GS Collections | Iteration patterns
17
AnySatisfy patternDetermine if any collection element satisfies a given logical expression.
The AnySatisfy method determines whether any element satisfies the Predicate. It applies the Predicate to eachelement. If the Predicate ever returns true, execution halts and the method returns true immediately. Otherwise, everyelement is checked and the method returns false.
Pseudocode for each <element> of <collection> if condition(<element>) return true otherwise return false
JDK for (int i = 0; i < list.size(); i++){ Integer v = list.get(i); if (v.intValue() > 50) { return true; }}return false;
GSC (Java 5+) return list.anySatisfy(Predicates.greaterThan(50));
GSC (Java 8) return list.anySatisfy(num -> num > 50);
AnySatisfy methods
anySatisfy(Predicate) : boolean
Return true if the Predicate returns true for any element of the collection. Otherwise (or if the collection is empty),return false.
anySatisfyWith(Predicate2, parameter) : boolean
Return true if the Predicate2 returns true for any element of the collection. Otherwise (or if the collection is empty),return false.
GS Collections | Iteration patterns
18
AllSatisfy patternDetermine if all collection elements satisfy a given logical expression.
The AllSatisfy method determines whether all elements satisfy the Predicate. It applies the Predicate to each element.If the Predicate ever returns false, execution halts and the method returns false immediately. Otherwise, everyelement is checked and the method returns true.
Pseudocodefor each <element> of <collection> if not condition(<element>) return false otherwise return true
JDK for (int i = 0; i < list.size(); i++){ Integer v = list.get(i); if (v.intValue() <= 50) { return false; }}return true;
GSC (Java 5+) return list.allSatisfy(Predicates.greaterThan(50));
GSC (Java 8) return list.allSatisfy(each -> each > 50);
NoneSatisfy is similar to AllSatisfy, but negates the Predicate. It returns true only if no element satisfies the Predicate.If the container is empty it also returns true.
AllSatisfy methods
allSatisfy(Predicate) : boolean
Return true if the Predicate returns true for all elements of the collection. Otherwise (or if the collection is empty),return false.
allSatisfyWith(Predicate2, parameter) : boolean
Return true if the Predicate2 returns true for all elements of the collection. Otherwise (or if the collection is empty),return false.
noneSatisfy(Predicate) : boolean
Return true if the Predicate returns false for all elements of the collection or if the collection is empty. Otherwise,return false.
noneSatisfyWith(Predicate2, parameter) : boolean
Return true if the Predicate2 returns false for all elements of the collection or if the collection is empty. Otherwise,return false.
ForEach patternPerform a calculation on each element of the current collection.
The ForEach pattern defines the most basic iteration operation that can be used with all collection types. Unlike theother patterns discussed in this topic, the ForEach pattern prescribes methods that operate on each element of thecalling collection object, with no value returned by the method itself.
GS Collections | Iteration patterns
19
In GS Collections, the forEach method offers the most straightforward replacement for the Java for loop. It executesthe code in a Procedure on each element. You can use these methods to perform some action using the values of thesource collection - for example, to print a value or to call another method on each element.
Pseudocode for each <element> of <collection> evaluate(<element>)
JDK for (int i = 0; i < list.size(); i++){ this.doSomething(list.get(i));}
GSC (Java 5+) list.forEach(new Procedure(){ public void value(Object each) { doSomething(each); }});
GSC (Java 8) Procedure run = each -> doSomething(each); list.forEach(run);
ForEach methods
forEach(Procedure) : void
For each element, the code block is evaluated with the element as the argument.
forEachIf(Predicate, Procedure) : void
For each element that satisfies the Predicate, executes the Procedure on that element.
forEach(fromIndex, toindex, Procedure) : void
Iterates over the section of a ListIterable covered by the specified indexes (inclusive).
forEachWith(Procedure2, parameter) : void
For each element of the collection, the code block is evaluated with the element as the first argument, and thespecified parameter as the second argument.
forEachWithIndex(ObjectIntProcedure) : void
Iterates over a collection passing each element and the current relative int index to the specified instance ofObjectIntProcedure.
forEachWithIndex(fromIndex, toIndex, ObjectIntProcedure) : void
Iterates over the section of the list covered by the specified indexes (inclusive).
InjectInto patternCalculate and maintain a running value during iteration; use each
evaluated result as an argument in the next iteration.
The InjectInto pattern is used to carry a computed result from one iteration as input to the next. In this pattern, theinjectInto method takes an initial injected value as a parameter. This value is used as the first argument to a two-argument code block; the current element (for each iteration of the collection) is taken as the second argument.
GS Collections | Iteration patterns
20
For each iteration, the code block's evaluation result is passed to the next iteration as the first argument (the injectedvalue) of the code block, with the (new) current element as the second argument. The injectInto() method returns thecode block's cumulative result upon the final iteration.
Pseudocode set <result> to <initialvalue> for each <element> of <collection> <result> = apply(<result>, <element>) return <result>
JDK List<Integer> list = Lists.mutable.of(1, 2);int result = 3;for (int i = 0; i < list.size(); i++){ Integer v = list.get(i); result = result + v.intValue();}
GSC (Java 5+) Lists.mutable.of(1, 2).injectInto(3, AddFunction.INTEGER);
GSC (Java 8) Lists.mutable.of(1, 2).injectInto(3, (result, each) -> Integer.valueOf(result + each));
InjectInto methods
injectInto(injectedValue, Function2) : (final result)
Return the final result of all evaluations using as the arguments each element of the collection, and the result of theprevious iteration's evaluation.
injectInto(floatValue, FloatObjectToFloatFunction) : float
Return the final result of all evaluations using as the arguments each element of the collection, and the result of theprevious iteration's evaluation. The injected value and result are both primitive floats.
injectInto(intValue, IntObjectToIntFunction) : int
Return the final result of all evaluations using as the arguments each element of the collection, and the result of theprevious iteration's evaluation. The injected value and final result are both primitive ints.
injectInto(longValue, LongObjectToLongFunction) : long
Return the final result of all evaluations using as the arguments each element of the collection, and the result of theprevious iteration's evaluation. The injected value and result are both primitive longs.
injectInto(doubleValue, DoubleObjectToDoubleFunction) : double
Return the final result of all evaluations using as the arguments each element of the collection, and the result of theprevious iteration's evaluation. The injected value and result are both primitive doubles.
RichIterableRichIterable is the most important interface in GS Collections. It provides the blueprint for all non-mutating iterationpatterns. It represents an object made up of elements that can be individually and consecutively viewed or evaluated(an iterable), and it prescribes the actions that can be performed with each evaluation (the patterns). The mostcommonly used implementations include FastList and UnifiedSet.
RichIterable is extended by ListIterable, SetIterable, Bag, StackIterable, and MapIterable. A MapIterable of keysand values is also a RichIterable of values.
RichIterable is also extended by MutableCollection, and indirectly by MutableList and MutableSet (whichalso extend the mutable Java Collection types List and Set). Another subinterface defines a non-JDK container,
GS Collections | Iteration patterns
21
MutableBag (or multiset); yet another, ImmutableCollection , delineates the immutable forms of these GSCollections containers. These latter two interfaces are detailed in the Collections and containers topic.
The subinterface LazyIterable for the most part replicates RichIterable, but overrides some specific collection-returning methods - collect, collectIf, select, reject, and flatCollect - so that they delay their actual execution untilthe returned collection is needed, a technique called "lazy iteration."
Lazy iterationDeferring evaluation until necessary.
Lazy iteration is an optimization pattern in which an iteration method is invoked, but its actual execution is deferreduntil its action or return values are required by another, subsequent method. In practical terms, the objective istypically to forestall unnecessary processing, memory use, and temporary-object creation unless and until they areneeded. Lazy iteration is implemented as an adapter on the current RichIterable collection by this method:
richIterable.asLazy() Returns a deferred-evaluation iterable. (Note the listbelow of other GS Collections methods that return lazyIterables.)
In a way, lazy iteration is a companion to the short-circuit iteration pattern, in which iteration ceases as soon themethod's purpose is achieved. In the last line of the example below, the anySatisfy method quits execution whenit detects the "address2" element in the addresses list created by collect. The third element ("address 3") is neverexamined by anySatisfy—although it was present in addresses.
GSC (Java 5+) Person person1 = new Person(address1); Person person2 = new Person(address2); Person person3 = new Person(address3); MutableList<Person> people = FastList.newListWith(person1, person2, person3); MutableList<MutableList<Address>> addresses = people.collect(addressFunction); Assert.assertTrue(addresses.anySatisfy(Predicates.equal(address2)));
One excess element out of three may be trivial, but if people were to be a very long list (or a stream), anySatisfy willstill have to wait for the collect method to finish aggregating an equally-large temporary collection—one that willhave only its first two elements inspected. By applying a lazy-iteration adapter to people, the collect iteration defersto that of anySatisfy: only the elements anySatisfy requires are "collected."
GSC (Java 5+) MutableList<Person> people = FastList.newListWith(person1, person2, person3); LazyIterable<Person> lazyPeople = people.asLazy(); LazyIterable<Address> addresses = lazyPeople.collect(addressFunction); Assert.assertTrue(addresses.anySatisfy(Predicates.equal(address2)));
This example demonstrates lazy iteration using both Java 8 lambdas and method references:
GSC (Java 8) LazyIterable<Person> lazyPeople = people.asLazy();
LazyIterable<Address> addresses = lazyPeople.flatCollect(person -> person.getAddress()); //orLazyIterable<Address> addresses = lazyPeople.flatCollect(Person::getAddress);
GS Collections | Iteration patterns
22
In this example, the values in a Multimap are flattened and sorted, the results processed and sent to a stream byforEach.
GSC (Java 5+) myMultimap.multiValuesView() // returns a lazy iterable by default .select(ITERABLE_SIZE_AT_THRESHOLD) // invoked but deferred .select(ITERABLE_SIZE_AT_THRESHOLD) // invoked but deferred .asSortedList(DESCENDING_ITERABLE_SIZE) // as "select" evaluates, // sort elements in a non-lazy // sorted list. .asLazy() // restores the lazy adapter .collect(ITERABLE_TO_FORMATTED_STRING) // invoked but deferred .collect(ITERABLE_TO_FORMATTED_STRING) // invoked but deferred .forEach(Procedures.println(System.out));// as "collect" evaluates, // send results to stream.
Because a lazy iterable adapter is used, the Collect evaluation occurs only as the ForEach evaluation calls for it;there is no intervening collection. Without the lazy adapter, collect would execute in full, then return a collection toforEach.
Finally, note these GS Collections methods that implicitly return a lazy-iterable type.
MutableMap interface and its implementations
valuesView() : RichIterable An unmodifiable view of the map's values.
keysView() : RichIterable An unmodifiable view of the map's keyset.
keyValuesView() : RichIterable An unmodifiable view of the map's entryset.
Multimap interface and its implementations
keyMultiValuePairsView() : RichIterable An unmodifiable view of key and multi-value pairs.
keysView() : RichIterable An unmodifiable view of unique keys.
keyValuePairsView() : RichIterable An unmodifiable view of key/value pairs.
multiValuesView() : RichIterable An unmodifiable view of each key's values, without thekey.
Parallel-lazy iterationAn API that combines parallel iteration with lazy evaluation.
Parallel-eager utility is available through the ParallelIterate utility class. Serial-lazy evaluation is available throughLazyIterable, the view returned by RichIterable.asLazy(). The ParallelIterable interface defines a view whereiteration is both parallel and lazy. Sub-interfaces of ParallelIterable are returned from the various implementations ofasParallel( ExecutorService executorService, int batchSize ). The ParallelIterable API is new in 5.0 and consideredexperimental, as indicated by the @Beta annotation. API tagged as @Beta may be altered in ways that are not
GS Collections | Iteration patterns
23
backward-compatible, even in minor versions of GS Collections. The method asParallel is not on interfaces likeRichIterable in version 5.0, but rather on a few supported collections, including FastList and UnifiedSet.
FastList integers = FastList.newListWith(1, 2, 3, 4, 5, 6, 7, 8, 9);
ExecutorService threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());int batchSize = 2;ParallelListIterable parallelListIterable = integers.asParallel(threadPool, batchSize);// deferred evaluationParallelListIterable evenNumbers = parallelListIterable.select(each -> each % 2 == 0);// deferred evaluationParallelListIterable evenStrings = evenNumbers.collect(Object::toString);// forced evaluationMutableList strings = evenStrings.toList();threadPool.shutdown();Assert.assertEquals(FastList.newListWith("2", "4", "6", "8"), strings);
In this code example, the calls to select and collect are lazy, as indicated by the fact that they return subclasses ofParallelIterable. The call to toList() forces evaluation.
The two parameters to asParallel(ExecutorService executorService, int batchSize) are used to configure parallelism.
executorService This code example set up a thread pool with one thread per core, which is appropriatefor CPU bound tasks. A thread pool used for IO bound tasks should be infinite orshould have one thread per IO-bound resource, for example, one thread per databaseconnection. It often makes sense to share thread pools between multiple calls toasParallel.
batchSize The batch size determines the number of elements from the backing collection(FastList or UnifiedSet) that get processed by each task submitted to the thread pool.Appropriate batch sizes for CPU-bound tasks are usually larger, in the 10,000 to100,000 range.
Performance
As with lazy evaluation, there is no guarantee that using parallel-lazy evaluation will yield better performance thansimple serial-eager evaluation. Performance testing is required, using an appropriate thread pool and trying variousbatch sizes.
Cancelability
It's possible to cancel a parallel-lazy computation in progress. It requires a thread pool that can be shut down, whichmeans it usually won't be a thread pool shared between multiple computations. Cancelling also requires a runnablethread with access to the thread pool. Building on the previous example, we just need to change evenStrings.toList()to execute in a background thread. Then the main thread could call threadPool.shutdownNow() which would causetoList() to terminate relatively quickly by throwing an exception. Shutting down the thread pool won't stop anybatches in progress. However, no new batches will be started.
RichIterable methodsThese methods are available on all implementations of RichIterable.
GS Collections | Iteration patterns
24
Building stringsMethods that convert collection elements to a string that can be
appended to a stream or buffer.
The makeString method returns a representation of the calling RichIterable collection as a String object. Elementsare converted to strings as they would be by String.valueOf(Object). You can specify start and end strings asdelimiters (the default is an empty string for both) and the separator string for the between-values delimiter (defaultsto comma and space).
makeString(startString, separatorString,endString) : String
Returns a string representation of the calling collection thatis a list of elements in the order they are returned by theiterator, enclosed in the startString and endString. Elementsare delimited by the separatorString.
makeString(separatorString) : String Same result with no starting and ending strings.
makeString() : String Same result with the default delimiter ", " (comma space) andno starting and ending strings.
GSC (Java 5+) MutableList<Integer> list = FastList.newListWith(1, 2, 3); String myDelim = list.makeString("[", "/", "]"); // "[1/2/3]" String mySeper = list.makeString("/"); // "1/2/3" String defaultString = list.makeString(); //"1, 2, 3"
The appendString method uses forms similar to makeString, but the string representation of the collection is writtento a Java Appendable object, such as a PrintStream, StringBuilder or StringBuffer; the method itself is void.
appendString(Appendable, startString, separatorString,endString) : void
Appends a string representation of this collectiononto the given Appendable using the specifiedstart, end, and separator strings
appendString(Appendable, separatorString) : void Appends with specified separator, but no startingor ending strings.
appendString(Appendable) : void Appends with the default delimiter ", " (commaspace) and no starting and ending strings.
GSC (Java 5+) MutableList<Integer> list = FastList.newListWith(1, 2, 3); Appendable myStringBuilder = new StringBuilder(); list.appendString(myStringBuilder, "[", "/", "]"); //"[1/2/3]");
Counting elementsGet the total number of elements that satisfy a condition.
The count and countWith methods calculate the number of collection elements that satisfy a given predicate. ThecountWith method takes a second parameter that is used as an additional argument in evaluating the current element.
count(Predicate) : int
Returns the number of elements that satisfy the Predicate. For example:
GSC (Java 5+) return people.count(new Predicate<Person>() { public boolean value(Person person) { return person.getAddress().getState().getName().equals("New York"); } });
GS Collections | Iteration patterns
25
Here is a Java 8 lambda example:
GSC (Java 8) return people.count(person -> person.getAddress().getState().getName().equals("New York"));
countWith(Predicate2, parameter) : int
Returns the number of elements that satisfy the Predicate2. The second parameter to countWith is passed as thesecond parameter to the Predicate2.
GSC (Java 5+) return lastNames.countWith(Predicates2.equal(), "Smith");
Use these methods to get the total number of collection items or to determine whether the collection is empty.
size() : int Returns the number of items in the collection.
isEmpty() : boolean Returns true if this iterable has zero items.
notEmpty() : boolean Returns true if this iterable has greater than zero items.
Finding elementsLocate elements by iteration position or highest/lowest value.
The getFirst and getLast methods return the first and last elements, respectively of a RichIterable collection. In thecase of a List, these are the elements at the first and last index. For all any other collections, getFirst and getLastreturn the first and last elements that would be returned by an iterator. Note that the first or last element of a hash-based Set could be any element, because element order in a hashed structure is not defined. Both methods return nullif the collection is empty. If null is a valid element, use the isEmpty method to determine if the container is in factempty.
getFirst() : elementReturns the first element of an iterable collection.
getLast() : elementReturns the last element of an iterable collection.
The min and max methods, without parameters, return an element from an iterable based on its natural order, that is,by calling the compareTo() method on each element.
max() : element Returns the maximum value based on the natural ordering.
min() : element Returns the minimum value based on the natural ordering.
GSC (Java 5+) RichIterable<Integer> iterable = FastList.newListWith(5, 4, 8, 9, 1); Assert.assertEquals(Integer.valueOf(9), iterable.max()); Assert.assertEquals(Integer.valueOf(1), iterable.min());
If any element in the iterable is not Comparable, then a ClassCastException is thrown.
GSC (Java 5+) RichIterable<Object> iterable = FastList.newListWith(5, 4, 8, 9, 1, new Foo()); iterable.max(); // throws ClassCastException
The min and max methods each have an overload that takes a Comparator that determines the natural order.
max(Comparator) : element Returns the maximum element out of this collection based on the comparator.
min(Comparator) : element Returns the minimum element out of this collection based on the comparator.
GS Collections | Iteration patterns
26
GSC (Java 5+) public class SillyWalk { public final int wiggles;
public SillyWalk(int wiggles) { this.wiggles = wiggles; }}
private static final Comparator<SillyWalk> SILLY_WALK_COMPARATOR = new Comparator<SillyWalk>() { public int compare(SillyWalk o1, SillyWalk o2) { return o1.wiggles - o2.wiggles; } };
SillyWalk sillyWalk2 = new SillyWalk(2); SillyWalk sillyWalk3 = new SillyWalk(3);
RichIterable<SillyWalk> walks = FastList.newListWith(sillyWalk2, sillyWalk3);
Assert.assertEquals(sillyWalk3,walks.max(SILLY_WALK_COMPARATOR)); Assert.assertEquals(sillyWalk2,walks.min(SILLY_WALK_COMPARATOR));
The related methods minBy and maxBy take a Function and return the minimum or maximum element in theRichIterable based on the natural order of the attribute returned by the Function.
maxBy(Function) : element Returns the maximum element out of this collection based on the result ofapplying the Function to each element.
minBy(Function) : element Returns the minimum element out of this collection based on the result ofapplying the Function to each element.
Here, we find the youngest person (the minimum person by age).
GSC (Java 5+) Person alice = new Person("Alice", 40); Person bob = new Person("Bob", 30); Person charlie = new Person("Charlie", 50);
MutableList<Person> people = FastList.newListWith(alice, bob, charlie);
Assert.assertEquals(bob, people.minBy(Person.TO_AGE));
In the code example we already had a Function, so calling minBy was more concise than calling min(). These twoforms are equivalent though.
GSC (Java 5+) people.minBy(Person.TO_AGE); people.min(Comparators.byFunction(Person.TO_AGE));
Aggregating elementsMethods that create maps of aggregated values by grouping them on a
calculated key.
aggregateBy groups the elements in the RichIterable by the Function. Then all the elements that map to the samekey are aggregated together using the Function2. The third parameter, a Function0, creates the initial value in eachaggregation. Aggregate results are allowed to be immutable as they will be replaced in the map.
aggregateBy is conceptually analogous to calling a groupBy method on a RichIterable to create a Multimap,andthen calling injectInto on each collection of the Multimap values to create a MapIterable.
aggregateInPlaceBy is similar to aggregateBy, but it mutates values in the output map instead of replacing them.Thus in this case, the aggregate results must be mutable.
GS Collections | Iteration patterns
27
aggregateBy(Function, Function0, Function2) : MapIterable Returns a MapIterable bygrouping results by keyssupplied by evaluating aFunction.
GSC (Java 5+) Function0<Integer> factory = new Function0<Integer>() { public Integer value() { return Integer.valueOf(0); } };
Function2<Integer, Integer, Integer> sumAggregator = new Function2<Integer, Integer, Integer>() { public Integer value(Integer aggregate, Integer value) { return aggregate + value; } };
Function<Integer, Integer> groupBy = new Function<Integer, Integer>() { public Integer valueOf(Integer integer) { return integer % 2; } }; FastList<Integer> integers = FastList.newListWith(1, 1, 1, 2, 2, 3); MutableMap<Integer, Integer> aggregation = integers.aggregateBy(groupBy, factory, sumAggregator); Assert.assertEquals(4, aggregation.get(0).intValue()); Assert.assertEquals(6, aggregation.get(1).intValue());
GSC (Java 8) FastList<Integer> integers = FastList.newListWith(1, 1, 1, 2, 2, 3);MutableMap<Integer, Integer> aggregation =integers.aggregateBy( integer -> integer % 2, () -> 0, Integer::sum);Assert.assertEquals(4, aggregation.get(0).intValue());Assert.assertEquals(6, aggregation.get(1).intValue());
GS Collections | Iteration patterns
28
aggregateInPlaceBy(Function, Function0, Function2) : MapIterable Same result with no startingand ending strings.
GSC (Java 5+) Function0<AtomicInteger> factory = new Function0<AtomicInteger>() { public AtomicInteger value() { return new AtomicInteger(0); } }; Procedure2<AtomicInteger, Integer> sumAggregator = new Procedure2<AtomicInteger, Integer>() { public void value(AtomicInteger aggregate, Integer value) { aggregate.addAndGet(value); } };
Function<Integer, Integer> groupBy = new Function<Integer, Integer>() { public Integer valueOf(Integer integer) { return integer % 2; } }; FastList<Integer> integers = FastList.newListWith(1, 1, 1, 2, 2, 3); MutableMap<Integer, AtomicInteger> aggregation = integers.aggregateInPlaceBy(groupBy, factory, sumAggregator); Assert.assertEquals(4, aggregation.get(0).intValue()); Assert.assertEquals(6, aggregation.get(1).intValue());
GSC (Java 8) FastList<Integer> integers = FastList.newListWith(1, 1, 1, 2, 2, 3);MutableMap<Integer, AtomicInteger> aggregation =integers.aggregateInPlaceBy( integer -> integer % 2, () -> new AtomicInteger(0), AtomicInteger::addAndGet)Assert.assertEquals(4, aggregation.get(0).intValue());Assert.assertEquals(6, aggregation.get(1).intValue());
Using chunk and zip to create collectionsGrouping and pairing elements of one or more collections.
The chunk method can be used to gather the elements of a collection into chunks; that is, it creates a collection madeup of collections of a specified fixed size (an integer). If the size doesn't divide evenly into the total of collectionelements, then the final chunk is smaller.
chunk(size) : RichIterable
Returns a new collection with the source collection's elements grouped in "chunks," with size elements in eachchunk, and the last chunk containing the remaining elements, if any.
GSC (Java 5+) MutableList<Integer> list = FastList.newListWith(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); RichIterable<RichIterable<Integer>> chunks = list.chunk(4);
System.out.println(chunks);
This example prints out:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
The zip method pairs up the elements of one RichIterable with those of second. If one of the two collections hasmore elements than the other, those remaining elements are dropped. The zipWithIndex method is a special case ofzip that pairs the elements in a collection with their index positions.
GS Collections | Iteration patterns
29
zip(RichIterable) : RichIterable
Returns a new RichIterable by combining, into pairs, corresponding elements from the calling RichIterablecollection and the RichIterable collection named in the parameter. If one of the two collections is longer, itsremaining elements are ignored..
GSC (Java 5+) MutableList<String> list1 = FastList.newListWith("One", "Two", "Three", "Truncated"); MutableList<String> list2 = FastList.newListWith("Four", "Five", "Six"); MutableList<Pair<String, String>> pairs = list1.zip(list2); System.out.println(pairs);
This example prints out:
[One:Four, Two:Five, Three:Six]
zipWithIndex() : RichIterable
Returns a new RichIterable consisting of the calling collection's elements, each paired with its index (beginningwith index 0).
GSC (Java 5+) MutableList<String> list = FastList.newListWith("One", "Two", "Three"); MutableList<Pair<String, Integer>> pairs = list.zipWithIndex(); System.out.println(pairs);
This example prints out:
[One:0, Two:1, Three:2]
Performance optimized methods: reusing two-argument code blocksUsing selectWith, rejectWith, and collectWith inside other iteration
patterns (or loops) where code blocks can be created outside of the outeriteration patterns or made static.
The collection-returning iteration methods—collect, select, and reject—each take a single parameter: a codeblock that itself takes a single argument. These patterns have alternate forms, methods named collectWith,selectWith, and rejectWith respectively. The same is true of the boolean-returning "short-circuit" methods, detect,anySatisfy, allSatisfy, and noneSatisfy; each has a counterpart having the suffix "With." All of these are available onRichIterable and its subinterfaces.
In each case, the "...With" form of the method takes two parameters:
• The first method parameter is a code block that itself takes two arguments; the first argument of the code block isthe current element with each iteration.
• The second method parameter is an object that is then passed to the code block as its second argument.
selectWith(Predicate2, argument) : RichIterable
rejectWith(Predicate2, argument) : RichIterable
For each element of the collection, Predicate2 is evaluated with the element as one argument, plus one additionalargument; selected or rejected elements are returned in a new collection of the same type.
collectWith(Predicate2, argument) : RichIterable
Same as the collect method, but two arguments are passed to the code block; returns a new collection of the sametype and size.
GS Collections | Iteration patterns
30
These " ...With" forms accomplish exactly the same actions as their basic counterparts. Although slightly moreverbose, they allow for a specific performance optimization, that is re-use of the code block with different arguments.Here is an example of select that finds the adults in a list of people. First, the JDK version, and then rewritten in GSCollections form:
JDK List<Person> people =...; List<Person> adults = new ArrayList<Person>(); for (Person person : people) { if (person.getAge() >= 18) { adults.add(person); } }
GSC (Java 5+) MutableList<Person> people =...; MutableList<Person> adults = people.select( new Predicate<Person>() { public boolean accept(Person each) { return each.getAge() >= 18; } });
Here's the same algorithm, again in GS Collections, this time using selectWith():
GSC (Java 5+) MutableList<Person> people =...; MutableList<Person> adults = people.selectWith( new Predicate2<Person, Integer>() { @Override public boolean accept(Person eachPerson, Integer age) { return eachPerson.getAge() > age; } }, 18);
In this single instance, there is no reason to write it out this longer way; the extra generality - making age the secondargument to the Predicate2 - is unnecessary.
It does make sense, however, if you wanted to filter on multiple ages: you could hold onto and re-use the Predicate2,thereby creating less garbage.
GSC (Java 5+) MutableList<Person> people =...; Predicate2<Person, Integer> agePredicate = new Predicate2<Person, Integer>() { @Override public boolean accept(Person eachPerson, Integer age) { return eachPerson.getAge() > age; } }; MutableList<Person> drivers = people.selectWith(agePredicate, 17); MutableList<Person> voters = people.selectWith(agePredicate, 18); MutableList<Person> drinkers = people.selectWith(agePredicate, 21);
collectWith, selectWith, and rejectWith work well with method references.
GSC (Java 8) MutableList<Person> drivers = people.selectWith(Person::isAgeGreaterThan, 17);MutableList<Person> voters = people.selectWith(Person:: isAgeGreaterThan, 18);MutableList<Person> drinkers = people.selectWith(Person:: isAgeGreaterThan, 21);
This style encourages adding more behavior to the classes held in the containers. This style works with any "...With"method in Java 8 or higher.
GS Collections | Iteration patterns
31
Map iteration methodsMethods for iterating over Maps and Multimaps.
The MapIterable and Multimap interfaces are associative arrays, meaning they contain key-value pairs. All of thekeys in a Map are unique; a Multimap can have multiple values associated with each key.
The Multimap interface does not extend MapIterable. Multimap has a number of subinterfaces, such asListMultimap, SetMultimap, and BagMultimap, each with custom behavior for how to handle the collection ofvalues associated with each key.
Creating iterable views of mapsWrapper classes that return an iterable view of a map; ForEach patterns
for Map containers.
These three methods each return an unmodifiable RichIterable view of a Map. They are essentially wrappers over themodifiable, non-lazy objects returned by the corresponding Java Collections Framework methods.
valuesView() : RichIterable (Maps and Multimaps) Returns an unmodifiable RichIterablewrapper over the values of the Map.
keysView() : RichIterable (Maps and Multimaps) Returns an unmodifiable RichIterablewrapper over the keySet of the Map.
keyValuesView() : RichIterable (Maps only) Returns an unmodifiable lazy iterable of key/valuepairs.
ForEach Iteration
These three methods call a code block for each element on a Map (all return void).
forEachKey(Procedure) : void Calls the Procedure on each key of the Map.
forEachValue(Procedure) : void Calls the Procedure on each value of the Map.
forEachKeyValue(Procedure2) : void Calls the Procedure on each key-value pair of the Map.
Collecting entriesGather entries from another collection into a Map
Use the collectKeysAndValues method to add all the entries derived from another collection into the current Map.
collectKeysAndValues(collection, keyFunction, valueFunction) : MutableMap
(Mutable maps only) The key and value for each entry is determined by applying the keyFunction andvalueFunction (in each case, a Function) to each item in collection. Each is converted into a key-value entry andinserted into the Map. If a new entry has the same key as an existing entry in the calling map, the new entry's valuereplaces that of the existing entry.
GS Collections | Iteration patterns
32
Finding, testing and putting valuesDetect a value by its key and, optionally, insert or return other values.
The updateValue…, getIfAbsent… and ifPresentApply methods locate a specified key and return a map value thatcorresponds to that key. Depending on whether a value is found at the given key, each method performs a specificaction.
add(Pair<K, V>) : value
Adds the given key-value pair to the map. It's a convenience method for working with Pairs, similar to put(K, V).
updateValue(key, Function0, Function) : value
If there is a value in the Map that corresponds to the specified key, applies the specified Function to the value andreplaces the value, otherwise applies the Function to the value supplied by the Function0 and puts the result as avalue in the map at the specified key.
updateValueWith(key, Function0, Function2, parameter) : value
If there is a value in the Map that corresponds to the specified key, applies the specified Function2 to the value andthe specified parameter and replaces the value with the result, otherwise applies the Function2 to the value suppliedby the Function0 and the parameter and puts the result as a value in the map at the specified key.
getIfAbsent(key, Function0) : element (or Function0 result)
Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the resultof evaluating the specified Function0 (here, specifically, a code block without parameters that returns some object).
getIfAbsentPut(key, value) : element
Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns specifiedvalue, and puts that value in the map at the specified key.
getIfAbsentPut(key, Function0) : element (or Function0 result)
Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the resultof evaluating the specified Function0, and puts that value in the map at the specified key
getIfAbsentPutWith(key, Function,parameter) : element (or Function result)
Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the resultof evaluating the specified one-argument Function using the specified parameter, and put that value in the map atthe specified key.
getIfAbsentWith(key, Function, parameter) : element (or Function result)
Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the resultof evaluating the specified Function and parameter.
ifPresentApply(key, Function) : (Function result)
If there is a value in the Map that corresponds to the specified key, returns the result of evaluating the specifiedFunction with the value, otherwise returns null.
GS Collections | Iteration patterns
33
Flipping mapsReturn a new associative array where the position of the keys and values
have been flipped
flip() : Multimap
Since the values in the MapIterable are not necessarily unique, flip() returns a Multimap instead of a MapIterable.
flipUniqueValues() : MapIterable
Similar to MapIterable.flip() but asserts that the values in the MapIterable are unique and thus returns MapIterableinstead of Multimap. Throws IllegalArgumentException if the MapIterable contains duplicate values.
GS Collections | Iteration patterns
34
35
Chapter
2Collections and containers
Topics:
• Basic collection types• Primitive collections• Creating and converting
collections• Protecting collections
What is perhaps most distinctive about the GS Collections collection classesis what (quite properly) is hidden: their implementation of iteration patterns.Through this encapsulation, GS Collections is able to provide optimizedversions of each method on each container. For example, the first of theclasses we'll discuss here, FastList, is array-based; it iterates using indexedaccess directly against its internal array.
We'll begin with the GS Collections implementations of types having analogsin the Java Collections Framework (JCF). We'll then discuss the new typesBag and Multimap, the Immutable collections, and protective wrappers.
GS Collections | Collections and containers
36
Basic collection typesThe most commonly-used GS Collections classes are FastList, UnifiedSet, and UnifiedMap. These collections serveas drop-in replacements for their corresponding types in the Java Collections Framework (JCF). Note that these GSCollections classes do not extend the JCF implementations; they are instead new implementations of both JCF and GSCollections interfaces, as this (highly-simplified) diagram summarizes:
The methods of the JCF types are primarily focused on adding or removing elements and similar, non-iterativeoperations. GS Collections interfaces provide methods for iteration patterns that for the most part, do not modify(mutate) the source collection, but rather return a new collection or information about the source collection.
ListIterableAn ordered collection that allows duplicate elements.
A ListIterable is a RichIterable which maintains its elements in insertion order and allows duplicate elements.
ListIterable has two mutable subinterfaces (MutableList and FixedSizeList) and one immutable subinterface(ImmutableList).
The ListIterable interface includes the binarySearch method, which is similar to the static method binarySearch onjava.util.Collections, but available from the object-oriented API.
MutableListA mutable ListIterable that implements java.util.List; the most common
implementation is FastList.
MutableList extends the JCF List interface and has the same contract. It also extends RichIterable , which providesthe iteration methods common to all collections.
The most common implementation of MutableList is FastList, which can be used to replace the familiarjava.util.ArrayList. Here is a comparison of how the two types can be created.
Class Example
ArrayList (JCF) List<String> comparison = new ArrayList<String>();comparison.add("Comcast");comparison.add("IBM");comparison.add("Microsoft");comparison.add("Microsoft");return comparison;
FastList (GSC) return FastList.newListWith("Comcast", "IBM", "Microsoft", "Microsoft");
GS Collections | Collections and containers
37
The MutableList interface includes the sortThis and reverse methods, which are similar to the static methods sortand reverse on java.util.Collections. Both are mutating methods. Here is an example of sort using the JDK API andthen GS Collections.
Class Example
ArrayList (JCF) Collections.sort(people, new Comparator<Person>(){ public int compare(Person o1, Person o2) { int lastName = o1.getLastName().compareTo(o2.getLastName()); if (lastName != 0) { return lastName; } return o1.getFirstName().compareTo(o2.getFirstName()); }});
FastList(GSC Java 5+)
people.sortThis(new Comparator<Person>() { public int compare(Person o1, Person o2) { int lastName = o1.getLastName().compareTo(o2.getLastName()); if (lastName != 0) { return lastName; } return o1.getFirstName().compareTo(o2.getFirstName()); } });
FastList(GSC Java 8)
people.sortThis((o1, o2) -> { int lastName = o1.getLastName().compareTo(o2.getLastName()); if (lastName != 0) { return lastName; } return o1.getFirstName().compareTo(o2.getFirstName()); });
MutableList adds a new method called sortThisBy, which takes an attribute from each element using a Function andthen sorts the list by the natural order of that attribute.
Class Example
ArrayList (JCF) Collections.sort(people, Functions.toComparator(Person.TO_AGE));
FastList(GSC Java 5+)
people.sortThisBy(Person.TO_AGE);
FastList(GSC Java 8)
// Using a method referencepeople.sortThisBy(Person::getAge);// Using a lambda expressionpeople.sortThisBy(person -> person.getAge());
Here is an example comparing reverse using the JCF and using GS Collections; both are mutating methods.
Class Example
ArrayList (JCF) Collections.reverse(people);
FastList (GSC) people.reverseThis();
GS Collections | Collections and containers
38
The toReversed method on MutableList lets you reverse a list without mutating it; that is, it returns a newMutableList. Here is an example of how to accomplish that in the JCF and in GS Collections.
Class Example
ArrayList (JCF) List<Person> reversed = new ArrayList<Person>(people)Collections.reverse(reversed);
FastList(GSC Java 5+)
MutableList<Person> reversed = people.toReversed();
The asReversed method returns a reverse-order view of the MutableList—a lazy iterable, like that returned byasLazy—that defers each element's evaluation until it is called for by a subsequent method.
Class Example
FastList(GSC Java 8)
ListIterable<Integer> integers = FastList.newListWith(1, 2, 3);// deferred evaluationLazyIterable<Integer> reversed = integers.asReversed();// deferred evaluationLazyIterable<String> strings = reversed.collect(String::valueOf);// forces evaluationMutableList<String> stringsList = strings.toList(); Assert.assertEquals(FastList.newListWith("3", "2", "1"), stringsList);
ArrayList to FastList
Here are some additional JCF to GS Collections refactoring examples.
Here is a Java Collections' ArrayList:
JCF List<Integer> integers = newArrayList<Integer>();integers.add(1);integers.add(2);integers.add(3);
And, here is the identical construction in GS Collections:
GSC (Java 5+) List<Integer> integers = new FastList<Integer>();integers.add(1);integers.add(2);integers.add(3);
In GS Collections, the static factory method newList can infer generic types
GSC (Java 5+) List<Integer> integers = FastList.newList();integers.add(1);integers.add(2);integers.add(3);
The GS Collections newListWith() method also provides varargs support, allowing any number of arguments
GSC (Java 5+) List<Integer> integers = FastList.newListWith(1, 2, 3);
You can also use the richer interface:
GSC (Java 5+) MutableList<Integer> integers = FastList.newListWith(1, 2, 3);
The list is never mutated; it can be made unmodifiable:
FastList.newListWith(1, 2, 3).asUnmodifiable();
GS Collections | Collections and containers
39
There is also a form of newList that takes another iterable
GSC (Java 5+) FastList.newList(list);
These refactorings are analogous for UnifiedSet and UnifiedMap.
SetIterableA collection that allows no duplicate elements.
A SetIterable is a RichIterable that allows no duplicate elements. It can be sorted or unsorted.
• A SortedSetIterable is a SetIterable that maintains its elements in sorted order.• An UnsortedSetIterable is a SetIterable that maintains its elements in a hash table in an unpredictable order.
UnsortedSetIterable has two mutable subinterfaces (MutableSet and FixedSizeSet) and one immutable subinterface(ImmutableSet).
MutableSetA mutable SetIterable that implements java.util.Set; the most common
implementation is UnifiedSet.
MutableSet extends the JCF Set interface and has the same contract. It also extends RichIterable, which providesthe iteration methods common to all collections. An attempt to add duplicate elements to a MutableSet containeris ignored without throwing an exception. The order in which the elements are processed during iteration is notspecified.
The most common implementation is UnifiedSet, which can be used to replace the familiar java.util.HashSet.
Class Example
HashSet (JDK) Set<String> comparison = new HashSet<String>();comparison.add("IBM");comparison.add("Microsoft");comparison.add("Oracle");comparison.add("Comcast");return comparison;
UnifiedSet (GSC) return UnifiedSet.newSetWith("IBM", "Microsoft", "Verizon", "Comcast");
MutableSortedSetContains unique items that are sorted by some comparator or their
natural ordering.
A MutableSortedSet follows the same contract as a MutableSet, but sorts its elements by their natural order, orthrough a comparator parameter set by the user. The implementation for MutableSortedSet is TreeSortedSet.
Here is an example of a MutableSortedSet containing numbers in reverse order:
GSC (Java 5+) MutableSortedSet<Integer> sortedSetA = TreeSortedSet.newSet(Collections.<Integer>reverseOrder());MutableSortedSet<Integer> sortedSetB = TreeSortedSet.newSet(sortedSetA.with(1).with(2, 3).with(4, 5, 6));
MapIterableA collection of key/value pairs.
The MapIterable interface (extending RichIterable) is the top-level interface for collections of key/value pairs.
GS Collections | Collections and containers
40
MapIterable has two mutable subinterfaces ( MutableMap and FixedSizeMap), one immutable subinterface(ImmutableMap). It is also is extended in mutable and immutable versions of maps with sorted elements(SortedMapIterable) and maps that allow lookup keys by (unique) values as well as the reverse (BiMap).
MutableMapA mutable MapIterable that implements java.util.Map; the most common
implementation is UnifiedMap.
The MutableMap interface defines an association of key/value pairs. It extends the MapIterable interface, whichfurnishes a set of iteration methods especially for the key/value structure of a Map collection. These includeunmodifiable views of keys, values or pair-entries using the keysView, valuesView and entriesView methods,respectively.
The mutable subinterfaces of MapIterable also extend the JCF Map interface.
The most common implementation of MutableMap is UnifiedMap, which can replace the Java class HashMap.
Class Example
HashMap (JDK) Map<Integer, String> map = new HashMap<Integer, String>();map.put(1, "1");map.put(2, "2");map.put(3, "3");
UnifiedMap(GSC)
MutableMap<Integer, String> map = UnifiedMap.newWithKeysValues(1, "1", 2, "2", 3, "3");
MutableSortedMapA sorted Map.
A MutableSortedMap follows the same contract as a MutableMap, but sorts its elements by their natural order, orthrough a comparator parameter set by the user. The implementation for MutableSortedMap is TreeSortedMap.
This code block creates a TreeSortedMap which sorts in reverse order:
GSC (Java 5+) MutableSortedMap<String, Integer> sortedMap = TreeSortedMap.newMapWith(Comparators.<String>reverseNaturalOrder(), "1", 1, "2", 3, "3", 2, "4", 1);
BiMapA map that allows users to add key-value pairs and look up from either
direction
BiMap is an interface that defines a bi-directional map, i.e, a map that allows users to look up from both directions.Both the keys and the values in a BiMap are unique.
BiMap extends MapIterable and MutableBiMap extends MutableMap. The standard implementation isHashBiMap.
GSC (Java 5+) MutableBiMap<Integer, String> biMap = HashBiMap.newWithKeysValues(1, "1", 2, "2", 3, "3");
The distinctive methods on MutableBiMap are put, forcePut and inverse.
GS Collections | Collections and containers
41
put() MutableBiMap.put behaves like put on a regular map, except that it throws an exceptionwhen you try to add a duplicate value.
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 since value "1" is already present
forcePut() MutableBiMap.forcePut behaves like MutableBiMap.put, except that it silently removesthe 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.forcePut(1, "2"); // replaces the [1,"1"] pair with [1, "2"] biMap.put(2, "2"); // removes the [1, "2"] pair before putting Assert.assertFalse(biMap.containsKey(1)); Assert.assertEquals(HashBiMap.newWithKeysValues(2, "1"), biMap);
inverse() MutableBiMap.inverse returns a reversed view of the BiMap. 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(1, inverse.get("1")); Assert.assertTrue(inverse.containsKey("3")); Assert.assertEquals(2, inverse.put("2", 4));
BagAn unordered collection that allows duplicates.
A Bag is a RichIterable that allows duplicate elements and efficient querying of the number of occurrences of eachelement. It can be sorted or unsorted.
• A SortedBag is a Bag that maintains its elements in sorted order.• An UnsortedBag is a Bag that maintains its elements in a hash table in an unpredictable order.
UnsortedBag has two subinterfaces, MutableBag and ImmutableBag. SortedBag has two subinterfaces,MutableSortedBag and ImmutableSortedBag.
A Bag is conceptually like a Map from elements to the number of occurrences of that element.
AppleFor example, this list:
Pear
Orange
Orange
Apple
Orange
could create this bag: Pear 1
Orange 3
Apple 2
GSC (Java 5+) return MutableBag < String > bag = HashBag.newBagWith("Apple", "Pear", "Orange", "Apple", "Apple", "Orange");
The distinctive methods on Bag are:
GS Collections | Collections and containers
42
occurrencesOf Returns the occurrences of a distinct item in the bag.
forEachWithOccurrences For each distinct item, with the number of occurrences, executes the specifiedprocedure.
toMapOfItemToCount Returns a map with the item type to its count as an Integer.
MutableBagA mutable unordered collection allowing duplicates; the most common
implementation is HashBag.The MutableBag interface includes methods for manipulating the number of occurrences of an item. For example,to determine the number of unique elements in a MutableBag, use the sizeDistinct method. The most commonimplementation of MutableBag is HashBag.
GSC (Java 5+) return MutableBag < String > bag = HashBag.newBagWith("Apple", "Pear", "Orange", "Apple", "Apple", "Orange");
The distinctive methods on MutableBag are:
addOccurrences(T item, int occurrences) Increments the count of the item in the bagby a count specified by occurrences.
removeOccurrences(Object item, int occurrences) Decrements the count of the item in the bagby a count specified by occurrences.
setOccurrences(T item, int occurrences) Mutates the bag to contain the specifiednumber of occurrences of the item.
MutableSortedBagA sorted collection that allows duplicates.
A MutableSortedBag is a Bagthat maintains order. It defaults to natural order, but can take a comparator to sort. Themost common implementation of MutableSortedBag is TreeBag which uses a SortedMap as its underlying data store.
For example, this MutableSortedBag would contain integers sorted in reverse order:
GSC (Java 5+) MutableSortedBag<Integer> revIntegers = TreeBag.newBagWith(Collections.reverseOrder(), 4, 3, 3, 2, 2, 2, 1, 1);
StackIterableA collection that maintains "last-in, first-out" order, iterating over
elements in reverse insertion order.
A StackIterable is a RichIterable enforcing a "last-in, first-out" order; its methods always iterate over elements inreverse insertion order, (beginning with the most-recently added element). For example the getFirst method returnsthe the last element to have been added — the "top" of the stack.
StackIterable has a mutable and an immutable subinterface (MutableStack and ImmutableStack, respectively).
GS Collections | Collections and containers
43
MutableStackA mutable collection that maintains "last-in, first-out" order, iterating
over elements in reverse insertion order.
The most common implementation of MutableStack is ArrayStack. The closest JCF equivalent to ArrayStack isjava.util.Stack, which extends Vector but does not enforce strict LIFO iteration.
The distinctive methods on MutableStack are push, pop, and peek.
push Adds a new element to the top of the stack
pop Returns the top (most recently-added) element and removes it from the collection.
pop(int count) Returns a ListIterable of the number of elements specified by the count, beginningwith the top of the stack.
peek Returns but does not remove the top element. Note that, on a stack, getFirstlikewise returns the top element, and that getLast throws an exception.
peek(int count ) Returns a ListIterable of the number of elements specified by the count, beginningwith the top of the stack; does not remove the elements from the stack.
peekAt(int index ) Returns the element at index.
ArrayStack can replace java.util.Stack.
Class Example
Stack (JCF) Stack stack = new Stack(); stack.push(1); stack.push(2); stack.push(3);
ArrayStack(GSC)
MutableStack mutableStack = ArrayStack.newStackWith(1, 2, 3);
MultimapA map-like container that can have multiple values for each key
In a Multimap container, each key can be associated with multiple values. It is, in this sense, similar to a Map, butone whose values consist of individual collections of a specified type, called the backing collection. A Multimap isuseful in situations where you would otherwise use Map<K, Collection<V>>.
Unlike the other basic GS Collections containers, Multimap does not extend RichIterable, but resides along with itssubinterfaces in a separate API. The RichIterable methods are extended by the backing collection types.
Depending on the implementation, the "values" in a Multimap can be stored in Lists, Sets or Bags. For example, theFastListMultimap class is backed by a UnifiedMap that associates each key with a FastList that preserves the orderin which the values are added and allows duplicate to be added.
A Multimap is the type returned by the groupBy method. Here is an example in which we group a list of words bytheir length, obtaining a Multimap with integer (word=length) keys and lists of words having that length for values.
This simple list: here produces a List-backed Multimap: key value<list>
are 1 a
a 3 are,few,are,not,too
few 4 here,that,long
GS Collections | Collections and containers
44
words 5 words
that
are
not
too
long
The code that performs this action uses the groupBy method.
GSC (Java 5+) MutableList<String> words = FastList.newListWith("here", "are", "a", "few", "words", "that", "are", "not", "too", "long");MutableListMultimap<Integer, String> multimap = words.groupBy(StringFunctions.length());
GSC (Java 8) MutableList<String> words = FastList.newListWith("here", "are", "a", "few", "words", "that", "are", "not", "too", "long");MutableListMultimap<Integer, String> multimap = words.groupBy(String::length);
The interface MutableListMultimap extends the Multimap interface and tells us the type of its backing collections.Since words is a MutableList, the output is a MutableListMultimap. The word "are" is allowed to occur twice in thelist at key 3.
If we change words to a MutableSet, the result will be a MutableSetMultimap, which will eliminate duplicate entries.
GSC (Java 5+) MutableSet<String> words = UnifiedSet.newSetWith("here", "are", "a", "few", "words", "that", "are", "not", "too", "long");MutableSetMultimap<Integer, String> multimap = words.groupBy(StringFunctions.length());
GSC (Java 8) MutableSet<String> words = UnifiedSet.newSetWith("here", "are", "a", "few", "words", "that", "are", "not", "too", "long");MutableSetMultimap<Integer, String> multimap = words.groupBy(String::length);
With duplicates removed, only four 3-letter words remain. key value <list>
1 a
3 too,are,few,not,
4 long,here,that
5 words
Primitive collectionsContainers for iterating over collections of Java primitives.
GS Collections has memory-optimized lists, sets, stacks, maps, and bags for all the primitive types: int, long, float,char, byte, boolean, short, and double.
The interface hierarchies for primitive types correspond closely with the interface hierarchy for regular Objectcollections. For example, the collection interfaces for int include the following:
interface analogous to
IntIterable RichIterable
MutableIntCollection MutableCollection
IntList ListIterable
GS Collections | Collections and containers
45
MutableIntList MutableList
Primitive Lists The primitive list implementations are backed by an array like FastList, but with a primitivearray instead of an Object[]. They are named IntArrayList, FloatArrayList etc.
BooleanArrayList is a special case. Current JVMs use one byte per boolean in aboolean[] (instead of one bit per boolean). Thus the BooleanArrayList is backed by ajava.util.BitSet as an optimization.
To create an IntArrayList, use one of the following:
IntArrayList emptyList = new IntArrayList();IntArrayList intList = IntArrayList.newListWith(1, 2, 3);IntArrayList listFromIntIterable = IntArrayList.newListWith(IntHashSet.newSetWith(1, 2, 3));
IntInterval An IntInterval is a range of ints that may be iterated over using a step value. (Similar toInterval, but uses primitive ints instead of the wrapper Integers.)
Assert.assertEquals(IntArrayList.newListWith(1, 2, 3), IntInterval.oneTo(3));Assert.assertEquals(IntArrayList.newListWith(1, 3, 5), IntInterval.oneToBy(5, 2));
Primitive Sets The primitive set implementations are hash-table backed. They are named IntHashSet,FloatHashSet etc. BooleanHashSet is implemented using a single integer to hold one offour possible states: ([], [F], [T], or [T, F]). All other sets use open addressing and quadraticprobing.
Primitive Stacks Similar to ArrayStack but optimized for primitives.
Primitive Bags Similar to HashBag, but both item and count are primitives.
Primitive Maps There are three types of primitive maps:
• Object To Primitive (ObjectIntHashMap, ObjectFloatHashMap etc.)• Primitive To Object (IntObjectHashMap, FloatObjectHashMap etc.)• Primitive To Primitive (IntIntHashMap, IntLongHashMap etc.)
All the maps use open addressing and quadratic probing.
There are some common arithmetic operations that can be performed on all primitive collections (except booleancollections).
IntArrayList intList = IntArrayList.newListWith(1, 2, 3);Assert.assertEquals(6, intList.sum());Assert.assertEquals(2, intList.average());Assert.assertEquals(2, intList.median());
GS Collections | Collections and containers
46
Primitive maps with numeric value types (not boolean or Object) have a method addToValue that adds the givenamount to the value at the given key and returns the updated value.
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);
All primitive collections have immutable counterparts, and unmodifiable and synchronized wrappers. See theProtecting collections topic for more information.
Creating and converting collectionsThe following methods can be used to convert one container type to another. All of these methods are onRichIterable. To create immutable and fixed-size collections, refer to Immutable collections.
toList() : MutableList Converts the collection to the default MutableListimplementation (FastList).
toSet() : MutableSet Converts the collection to the default MutableSetimplementation (UnifiedSet).
toBag() : MutableBag Converts the collection to the default MutableBagimplementation (HashBag).
toMap(keyFunction, valueFunction) : MutableMap Converts the collection to the default MutableMapimplementation (UnifiedMap) using the specifiedkeyFunctions and valueFunctions.
toSortedList() : MutableList Converts the collection to the default MutableListimplementation (FastList) and sorts it using the naturalorder of the elements.
toSortedList(Comparator) : MutableList Converts the collection to the default MutableListimplementation (FastList) and sorts it using thespecified Comparator.
These methods always return new mutable copies: for example, calling toList on a FastList, returns a new FastList.
To create a new collection of the same type
newEmpty()> : MutableCollection Creates a new, empty, and mutable container of thesame collection type. For example, if this instance is aFastList, this method will return a new empty FastList.If the class of this instance is immutable (see below) orfixed size (for example, a singleton List) then a mutablealternative to the class is returned.
Protecting collectionsGS Collections provides special interfaces for controlling and preventing changes to containers and their elements.
• Immutable collection: a copy that is permanently unchangeable.• Unmodifiable collection: a read-only interface wrapped over a backing collection that remains mutable.
GS Collections | Collections and containers
47
• Synchronized collection: a wrapper that presents a mostly thread-safe view of a collection.
Immutable collectionsA read-only snapshot of a collection; once created, it can never be
modified.
All of the basic containers in GS Collections have interfaces for both mutable and immutable (unchangeable) forms.This departs somewhat from the JCF model, in which most containers are mutable.
An immutable collection is just that—once created, it can never be modified, retaining the same internal referencesand data throughout its lifespan. An immutable collection is equal to a corresponding mutable collection with thesame contents; a MutableList and an ImmutableList can be equal.
Because its state does not change over time, an immutable collection is always thread-safe. Using immutablecollections where feasible can serve to make your code easier to read and understand.
All of the interfaces and implementations discussed so far in this topic have been mutable versions of their respectivetypes. Each of these containers has an immutable counterpart. These are the corresponding interfaces:
Mutable types Immutable types
MutableList ImmutableList
MutableSet ImmutableSet
MutableBag ImmutableBag
MutableMap ImmutableMap
MutableMultimap ImmutableMultimap
MutableStack ImmutableStack
The method that returns an immutable collection for all container types is toImmutable():
MutableCollection. toImmutable() : ImmutableCollection
Returns an immutable copy of a type corresponding to the source MutableCollection.
StackIterable. toImmutable() : ImmutableStack
Returns an immutable copy of a MutableStack, returns the same iterable for an ImmutableStack.
ListIterable. toImmutable() : ImmutableList
Returns an immutable copy of a MutableList, returns the same iterable for an ImmutableList.
SortedMapIterable. toImmutable() : ImmutableSortedMap
Returns an immutable copy of a MutableSortedMap, returns the same iterable for an ImmutableSortedMap.
UnsortedMapIterable. toImmutable() : ImmutableMap
Returns an immutable copy of a MutableMap, returns the same iterable for an ImmutableMap.
An immutable-collection interface lacks mutating methods, such as add and remove. Instead, immutable collectionshave methods that return new, immutable copies with or without specified elements:
GS Collections | Collections and containers
48
ImmutableCollection. newWith(element) : ImmutableCollection
Returns a new immutable copy of ImmutableCollection with element added.
ImmutableCollection. newWithAll(Iterable) : ImmutableCollection
Returns a new immutable copy of ImmutableCollection with the elements of Iterable added.
ImmutableCollection. newWithout(element) : ImmutableCollection
Returns a new immutable copy of ImmutableCollection with element removed.
ImmutableCollection. newWithoutAll(Iterable) : ImmutableCollection
Returns a new immutable copy of ImmutableCollection with the elements of Iterable removed.
Note that the iteration methods of an immutable container - such as select, reject, and collect - also produce newimmutable collections.
Immutable Collection Factory Classes
The factory classes Lists, Sets, Bags, and Maps create immutable collections. These factories also provide methodsfor creating fixed-size collections, which have been superseded by immutable collections.
GSC (Java 5+) ImmutableList<Integer> immutableList = Lists.immutable.of(1, 2, 3);ImmutableSet<Integer> immutableSet = Sets.immutable.of(1, 2, 3);Bag<Integer> immutableBag = Bags.immutable.of(1, 2, 2, 3);ImmutableMap<Integer, String> immutableMap = Maps.immutable.of(1, "one", 2, "two", 3, "three");
These factories highlight yet another benefit of immutable collections: they let you create efficient containers that aresized according to their contents. In cases where there are many, even millions of collections, each with a size lessthan 10, this is an important advantage.
Protective wrappersWrapper classes providing read-only or thread-safe views of a
collection.
Unmodifiable Collections
In both the JCF and GS Collections, a collection may be rendered unmodifiable. In GS Collections, this is done bymeans of the asUnmodifiable method, which returns a read-only view of the calling collection. This means that themutating methods of the collection (e.g., add, remove) are still present, but throw exceptions if called.
MutableCollection. asUnmodifiable() : MutableCollection (read-only)
Returns a read-only view of the source collection.
MutableIntCollection.asUnmodifiable() : MutableIntCollection.(read-only)
Returns a read-only view of the source primitive collection. There are similar methods for each primitive type(MutableFloatCollection.asUnmodifiable() etc.)
Synchronized CollectionsGS Collections provides a wrapper for rendering a modifiable but thread-safe view that holds a lock when a method iscalled and releases the lock upon completion.
GS Collections | Collections and containers
49
MutableCollection. asSynchronized() : MutableCollection
Returns a synchronized copy of the source collection.
MutableIntCollection. asSynchronized() : MutableIntCollection.
Returns a synchronized copy of the source primitive collection. There are similar methods for each primitivetype (MutableFloatCollection.asSynchronized() etc.)
GS Collections | Collections and containers
50
51
Chapter
3Code blocks
Topics:
• Predicate• Function• Procedure
A code block, in GS Collections terms, is a single-abstract-method objectthat is passed as a parameter to an iteration method. It is an abstraction thatrepresents the evaluation of each element in the course of iteration. It helpsus to further separate what is being done from how it is done. This topicenumerates the basic code block types - the GS Collections interfaces andclasses - and the relevant methods to which they apply.
What we call a "code block" in GS Collections is roughly analogous to alambda expression. The closest analog to a lambda in Java in versions prior toJava 8 is the anonymous inner class.
Here are two examples, one implementing Predicate using an anonymousinner class, and the other using a Java 8 lambda expression.
GSC (Java 5+)
MutableList<Person> texans = this.people.select(new Predicate<Person>() { public boolean accept(Person each) { return each.getAddress().getState().equals("TX"); }});Verify.assertSize(1, texans);
GSC (Java 8)
MutableList<Person> texans = this.people.select( each -> each.getAddress().getState().equals("TX"));Verify.assertSize(1, texans);
In each case, if the value of state field for any element in people equals "TX"then the select method includes that element in the result list, texans.
This chapter introduces the most commonly-used code blocks and the GSCollections methods that use them. Along with the code block types describedhere, the current version of GS Collections offers a full suite of primitivecode blocks (and corresponding code block factories like IntFunction,IntPredicate, IntProcedure etc.) These code blocks are used by methods onprimitive collections.
About parameter and argument:
These terms are often (if inaccurately) used interchangeably to refer tomethod or function inputs. (The usual distinction holds that parameter refersto a formal definition of the input, while argument denotes the actual values.)For the limited purposes of this guide - and in particular the scope of thistopic - we use parameter to specify the input to an iteration method - in thisexample, select. These parameters can take the form of the code block (asdescribed in this topic), which itself is an object with methods. The input for a
GS Collections | Code blocks
52
code block we refer to here as the argument - in this example, the argument iseach (the "current element" upon each iteration).
GS Collections | Code blocks
53
PredicateA Predicate is a single-argument code block that evaluates an element and returns a boolean value. Also known as adiscriminator or filter, it is used with the filtering methods select, reject, detect, anySatisfy, allSatisfy, and count.
Description Arguments Returns Used By
Predicate Evaluates each element of acollection (the argument), and returnsa boolean value.
One (T) boolean select, reject,detect,anySatisfy,allSatisfy, count
Predicate2 Evaluates each element of acollection (the first argument); thesecond argument is a parameterpassed into the Predicate2 from thecalling method.
Two (T,P) boolean selectWith,rejectWith,detectWith,anySatisfyWith,allSatisfyWith,countWith
The accept method is implemented to indicate the object passed to the method meets the criteria of this Predicate.Here is a Predicate implemented in a select method as an anonymous inner class:
GSC (Java 5+) MutableList<Integer> greaterThanFifty = list.select(new Predicate<Integer>() { public boolean accept(Integer each) { return each > 50; } });
The Predicates class can be used to build common filters. Predicates supports equals, not equals, less than, greaterthan, less than or equal to, greater than or equal to, in, not in, and, or, and numerous other predicate-type operations.
Examples with select:
GSC (Java 5+) MutableList<Integer> myList =...MutableList<Integer> selected1 = myList.select(Predicates.greaterThan(50));
Predicate Factories
Predicates Supports equal, greaterThan, lessThan, in, notIn, and, or,instanceOf, null, notNull, anySatisfy, allSatisfy, etc.
Predicates2 For Predicate2s that work with methods suffixed with"With," such as selectWith.
StringPredicates Supports empty, notEmpty, contains, isAlpha,isNumeric, isBlank, startsWith, endsWith, matches, etc.
IntegerPredicates Supports isEven, isOdd, isPositive, isNegative, isZero.
LongPredicates Supports isEven, isOdd, isPositive, isNegative, isZero.
FunctionThe Function code block in its most common usage takes each element of a collection as the argument to the code-block logic. It selects an attribute from the element via a "getter" – its valueOf method. It then returns a computedvalue or, if no evaluation logic is performed, the attribute itself.
GS Collections | Code blocks
54
Function code blocks are used as a parameter in a variety of common GS Collections methods:
• With the collect method to calculate a new value for each element of a given collection, and then return atransformed collection of the same type.
• With the groupBy method to generate keys for each nested collection (values) of a new Multimap.• With the flatCollect method, where it must return an Iterable that gets "flattened" with other iterables, into a
single collection.• With the Predicates factory's attributeOperator methods - such as attributeLessThanOrEqualTo - to build
Predicate (boolean) objects.
Description Arguments Returns Used By
Function(transformer)
Evaluates each element of acollection as the argument to the codeblock logic and returns a computedvalue
One (T) Object (V) collect,flatCollect,groupBy
Function0 Executes and returns a value (likeCallable); represents deferredevaluation.
Zero Object (V) getIfAbsent,getIfAbsentPut,ifPresentApply
Function2 Used by injectInto methods; takesthe accumulator argument as the firstargument, and the current item of thecollection as the second argument.
Two (T,P) Object (V) forEachEntryinjectIntocollectWith
Function3 Used by injectIntoWith; takesthe injected argument as the firstargument, the current item of thecollection as the second argument,and the specified parameter for thethird argument. The result of eachsubsequent iteration is passed in asthe first argument.
Three (T,P,?) Object (V) injectIntoWith
Function Factories
FunctionsgetToClass getToString
getPassThru
Functions0newFastList newHashBag
newUnifiedMap newUnifiedSet
nullValue value
Functions2 fromFunction
StringFunctionsfirstLetter length
subString toFirstChar
toInteger toLowerCase
toPrimitive [type] toUpperCase
trim firstLetter
GS Collections | Code blocks
55
Other Functions
IfFunction Supports if and else using a discriminator with Function.
CaseFunction This allows for multi-conditional or rule based selector using Predicates (use this withguidance).
ProcedureA Procedure is a code block that performs an evaluation on its single argument and returns nothing. A Procedure ismost commonly used with ForEach -pattern methods.
Count and calculate
CountProcedure Apply a Predicate to an object and increment a count if it returns true.
CounterProcedure Wrap a specified block and keeps track of the number of times it is executed.
Control execution
ChainedProcedure Chain together blocks of code to be executed in sequence;ChainedProcedure can chain Procedures, Functions or Function2s.
CaseProcedure Create an object form of a case statement, which instead of being based on asingle switch value is based on a list of discriminator or block combinations.For the first discriminator that returns true for a given value in the casestatement, the corresponding block will be executed.
IfProcedure Evaluate the specified block only when a Predicate returns true. If the resultof evaluating the Predicate is false, and the developer has specified that thereis an elseProcedure, then the elseProcedure is evaluated.
IfProcedureWith Same as IfProcedure, but with a second argument passed from the callingiteration method.
ObjectIntProcedure Takes an int as a second argument; this is usually the index of the currentelement of a collection.
Modify collections and maps
CollectionAddProcedure Add elements to the specified collection when block methods arecalled.
CollectionRemoveProcedure Remove element from the specified collection when block methodsare called.
MapPutProcedure Use a specified Function to calculate the key for an object and putsthe object into the specified Map at the position of the calculatedkey.
MultimapPutProcedure Use a specified Function to calculate the key for an object and putsthe object with the key into the specified MutableMultimap.
GS Collections | Code blocks
56
Procedure Factories
Proceduresappend bind
caseDefault fromObjectIntProcedure
ifElse ifTrue
println synchronizedEach
Procedures2addToCollection fromProcedure
57
Appendix
AHelp
Topics:
• Verify• Q & A• GS Collections Cheat Sheet
Additional reference pages.
GS Collections | Help
58
VerifyA testing utility.
GS Collections includes a jar file called gs-collections-testutils. This utility helps with writing unit tests. There aremany collection-specific assertions, such as
MutableList<Integer> list = FastList.newListWith(1, 2, 3);Verify.assertListsEqual(FastList.newListWith(1, 2, 3), list);
to test that two lists are equal. It is implemented as an extension of JUnit. The most important class is Verify. Hereare some examples:
Verify.assertSize(2, customersFromLondon);
//instead ofAssert.assertEquals(2, customersFromLondon.size());
Verify.assertEmpty(FastList.newList());Verify.assertNotEmpty(FastList.newListWith(1));Verify.assertContains(1, FastList.newListWith(1));
Q & A
Here are some of the most commonly asked questions and answers regarding GS Collections.
Why GS Collections?
• Improves readability and reduces duplication of iteration code (enforces DRY/OAOO).• Implements several high-level iteration patterns (select, reject, collect, inject into, etc.) on "humane" container
interfaces which are extensions of the JDK interface.• Provides a consistent mechanism for iterating over Collections, Arrays, Maps, and Strings.• Provides replacements for ArrayList, HashSet, and HashMap optimized for performance and memory usage.• Performs more "behind-the-scene" optimizations in utility classes.• Encapsulates a lot of the structural complexity of parallel iteration and lazy evaluation.• Adds new containers including Bag, Interval, Multimap, and immutable versions of all types.• Has been under active development since 2005 and is a mature library.
Why is Goldman Sachs open-sourcing GS Collections?
• We believe that GS Collections offers a significant advantage over existing solutions. We hope others will benefitfrom it.
• We believe in the power of the technical community to help improve GS Collections.• Technology is a huge part of what we do at Goldman Sachs. GS Collections exemplifies our commitment to
technology.• We use open source software in many of our operations. We have benefited from the work of others and we'd like
to give something back.
Does Goldman Sachs use GS Collections?
Yes, we use GS Collections in many of our internal applications.
What makes GS Collections different from other, similar frameworks?
The most obvious distinction for Java developers is the placement of collection-related iteration methods on thecontainer class itself. This means we can implement methods that are common to all container types, and optimizethem - in terms of memory and processor use - specifically for each type. The resulting code is easier (for humans) toread and understand.
GS Collections | Help
59
When can I start using Java 8 lambdas and method references with GS Collections?
GS Collections is Java 8 ready today! All of our iteration patterns are able to fully function as seen in the codeexamples of the reference guide.
GS Collections Cheat SheetRichIterable API Description
allSatisfy Returns true if all elements satisfy a Predicate; short-circuits execution.
anySatisfy Returns true if any element satisfies a Predicate; short circuits execution.
appendString Prints a string representation of this collection onto the given Appendable; prints the stringreturned by makeString.
asSynchronized Returns a synchronized collection.
asUnmodifiable Returns an unmodifiable collection.
chunk Splits a collection into fixed-size chunks; the final chunk will be smaller if the collectiondoesn't divide evenly.
collect Transforms elements using a Function into a new collection; n.
count Returns the number of elements that satisfy a Predicate.
detect Finds the first element that satisfies a Predicate; short circuits execution
flatCollect Transforms and flattens elements using a Function.
forEach Executes a Procedure on each element, doesn't return anything
groupBy Gets a key for each element using a Function and puts the key and element into a Multimap.
groupByEach Special case of groupBy used were the Function returns a collection; analogous to thedifference between collect and flatCollect.
injectInto Returns the final result of all evaluations using as the arguments each element of thecollection, and the result of the previous iteration's evaluation.
makeString Converts the collection to a string using optional start, end, and separator strings.
max Returns the maximum element using either the natural order or a Comparator.
maxBy Gets some attribute from each element and returns the element whose attribute is maximal.
min Returns the minimum element using either the natural order or a Comparator.
minBy Gets some attribute from each element and returns the element whose attribute is minimal.
reject Returns the elements of a collection that do not satisfy a Predicate.
select Returns the elements of a collection that satisfy a Predicate.
sortThis Sorts the internal data structure of a MutableList using the natural order of the elements or aComparator.
sortThisBy Gets some attribute from each element using a Function and sorts the list by the naturalorder of that attribute.
toBag Converts the collection to the default MutableBag implementation.
toImmutable Returns an immutable collection.
GS Collections | Help
60
RichIterable API Description
toList Converts the collection to a MutableList implementation.
toMap Converts collection to a MutableMap implementation using specified key and valuefunctions.
toSet Converts the collection to a MutableSet implementation.
toSortedList Converts the collection to a MutableList implementation and sorts it using the natural orderof the elements.
toSortedListBy Gets some attribute from each element using a Function and returns a new list sorted by thenatural order of that attribute.
toSortedSet Converts the collection to a MutableSortedSet implementation and sorts it using the naturalorder of the elements.
toSortedSetBy Converts the collection to a MutableSortedSet implementation and sorts it based on thenatural order of the attributes returned by the Function.
zip Takes a second RichIterable and pairs up all the elements; if one of the two RichIterables islonger, its remaining elements are ignored.
zipWithIndex Zips the collection with the Integer indexes 0 to n-1.
Interfaces Description
Bag Analogous to JCF Map <K, Integer>.
Multimap Analogous to JCF Map <K, Iterable<V>>.
MutableList Analogous to JCF List .
MutableMap Analogous to JCF Map .
MutableSet Analogous to JCF Set .
Pair Container that holds two related objects.
Blocks Description
Function Transforms one type (T) to another (V).
Function0 A zero-argument lambda (Java 8) that returns some type; a factory.
Function2 Used by injectInto methods; takes the accumulator argument as the first argument, and thecurrent item of the collection as the second argument.
ObjectIntProcedure Takes an int as a second argument; this is usually the index of the current element of acollection; doesn't return anything.
Predicate Takes an object of some type (T) and returns a boolean.
Predicate2 Primarily used in methods like selectWith, detectWith, rejectWith. The first argument isthe element of the collection being iterated over, and the second argument is a parameterpassed into the Predicate2 from the calling method.
Procedure Takes an object of some type (T) and doesn't return anything.
Procedure2 Takes two objects of types (T1, T2) and doesn't return anything.
GS Collections | Help
61
Static utility Classes To interoperate with
ArrayIterate Arrays
Iterate All iterables
LazyIterate All iterables for lazy evaluation
ListIterate Lists
MapIterate Maps
ParallelArrayIterate Arrays for parallel iteration
ParallelIterate Iterables for parallel iteration
ParallelMapIterate Maps for parallel iteration
StringIterate strings
GS Collections | Help
62