GS Collections User Reference Guide - Goldman Sachs

36 downloads 733 Views 493KB Size Report
greaterThan(50));. Here is an example of GS Collections using the proposed Lambda support that is being built in Java 8: GSC. List greaterThanFifty =.
GS Collections User Reference Guide Copyright © 2011 Goldman Sachs. All Rights Reserved.

Version 1.2.0 (03/14/2012)

Contact: [email protected]

GS Collections

GS Collections | TOC

Contents About GS Collections............................................................................................................5

Chapter 1: Iteration patterns..........................................................................7 Common iteration patterns....................................................................................................................... 8 Select/Reject pattern.....................................................................................................................8 Collect pattern............................................................................................................................ 10 Short-circuit patterns.................................................................................................................. 13 ForEach pattern.......................................................................................................................... 15 InjectInto pattern........................................................................................................................ 16 RichIterable............................................................................................................................................ 17 Lazy iteration..............................................................................................................................17 RichIterable methods..................................................................................................................18 Map iteration methods............................................................................................................................24 Creating iterable views of maps................................................................................................. 24 Collecting entries........................................................................................................................24 Finding, testing and putting values............................................................................................ 25

Chapter 2: Collections and containers.........................................................27 Basic collection types.............................................................................................................................28 MutableList................................................................................................................................ 28 MutableSet................................................................................................................................. 29 MutableMap............................................................................................................................... 30 MutableBag................................................................................................................................ 30 Multimap.................................................................................................................................... 31 Creating and converting collections....................................................................................................... 32 Protecting collections............................................................................................................................. 32 Immutable collections................................................................................................................ 32 Protective wrappers.................................................................................................................... 34

Chapter 3: Code blocks................................................................................. 35 Common code block types..................................................................................................................... 36 Predicate..................................................................................................................................... 36 Function......................................................................................................................................37 Procedure...................................................................................................................................37

Chapter 4: Utility GS Collections.................................................................41 Utility iteration patterns......................................................................................................................... 42 Parallel iteration..................................................................................................................................... 43

3

GS Collections | TOC

4

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 of new 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 collection classes, a concept derived from the Smalltalk language. Internal iteration affords a more consistent and intuitive approach to using collections by encapsulating the details of how various iteration patterns are implemented. Hiding this 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 highlevel 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.

5

GS Collections | About GS Collections

6

Chapter

1 Iteration patterns Topics: • • •

Common iteration patterns RichIterable Map iteration methods

GS Collections extends the Java Collections Framework with new interfaces and classes and provides additional methods. These new methods implement iteration patterns derived from the collection protocol of the Smalltalk language (e.g., select, reject, collect, detect). In idiomatic Java, iteration is performed by external for and while loops that enclose a block of business logic to be performed on each element of a collection. This is an approach that often leads to much duplication of code structure. In GS Collections, business logic is reified as a code block: a class that is passed as a parameter to an iteration method. Each implementation of an iteration method iterates over the collection, passing each element to the code block for processing. The most important advantage of internal iteration patterns is that they increase readability by giving names to the structural iteration patterns and by reducing code duplication. Moreover, by encapsulating implementation within specialized collection types (e.g., list, sets, maps), iteration can be optimized for the particular type.

7

GS Collections | Iteration patterns

Common iteration patterns The most commonly-used iteration patterns in GS Collections are: •

Filtering patterns: • • •



Transforming patterns: • • •



Collect Flatten GroupBy

"Short-circuit" patterns: • • •



Select Reject Partition

Detect AnySatisfy AllSatisfy

Generic action patterns: • •

ForEach InjectInto

Select/Reject pattern Filter 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 that satisfy some logical condition; Reject is the inverse pattern, returning a new collection of elements that do not satisfy the condition. The condition is a boolean expression in the form of single-argument code block that implements the Predicate interface. Select pattern examples: Pseudocode

create for each of if condition() add to

JDK List greaterThanFifty = new ArrayList(); for (Integer each : list) { if (each.intValue() > 50) { greaterThanFifty.add(each); } }

Select, using an anonymous inner class as a code block: GSC MutableList greaterThanFifty = list.select(new Predicate()

8

GS Collections | Iteration patterns

{ public boolean accept(Integer each) { return each > 50; } });

Here, a Predicate is created using the Predicates factory: GSC list.select(Predicates.greaterThan(50));

Here is an example of GS Collections using the proposed Lambda support that is being built in Java 8: GSC List greaterThanFifty = list.select(each - > each > 50);

Reject pattern examples: Pseudocode

create for each of if not condition() add to

JDK List notGreaterThanFifty = new ArrayList(); for (Integer each : list) { if (each = 18; } }); MutableList adults = partitionedFolks.getSelected(); MutableList children = partitionedFolks.getRejected();

Partitioning Methods partition(Predicate) Filters the collection into two separate new collections (selected and rejected), based on Predicate. The collections are returned in a specialized PartitionIterable of the same type as the source collection.

Collect pattern Transform 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 performed by the code block; that is, each element of the original collection is mapped to a new object, which is usually a different type. The code block used as the collect method's parameter implements the Function interface. Pseudocode

create for each of = transform() add to

JDK List addresses = new ArrayList(); for (Person person : people) { addresses.add(person.getAddress()); }

GSC MutableList people =...; Function addressFunction = new Function() { public Address valueOf(Person person) {

10

GS Collections | Iteration patterns

return person.getAddress(); } }; MutableList addresses = people.collect(addressFunction);

Notice that this assumes each person in the people collection has just one address. If, instead, a person has multiple addresses, the Function returns a list of addresses for each person (a list that has only one element if the person has just one address); the result is a List of Lists: GSC MutableList people =...; Function addressFunction = new Function() { public MutableList valueOf(Person person) { return person.getAddresses(); } }; MutableList addresses = people.collect(addressFunction);

Other Collect-style patterns GS Collections provides two specialized variations on the Collect pattern: Flatten and GroupBy. Both patterns, like Collect, use an code block implementing a Function to access and transform element values and return a collection.

Collect methods These GS Collections methods implement the Collect pattern: collect(Function) For each element of the collection, the Function is evaluated with the current element as the argument; returns a new collection of the same size and the transformed type. collect(Function, targetCollection) Same as collect, except that the results are added to the specified targetCollection. collectIf(Predicate, Function) Same as collect, except that the Predicate is first evaluated with the element as the argument to filter the collection. collectIf(Predicate, Function, targetCollection) Same as collectIf, except that the results are added to the specified targetCollection. collectWith(Predicate2, argument2) 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) Same as collectWith, except that the results are added to a specified targetCollection.

11

GS Collections | Iteration patterns

Flatten pattern Create 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," collection of attribute values from a source collection's elements. flatCollect(Function) Extract (and, optionally, transform) a selected attribute value from each of the calling collection's elements and add the values to a new single-level collection (e.g., a List or Set). Given list of people (as in the Collect example), here is how flatCollect could be used to create a flat list from the address fields of the person objects in that list, using the same Function (addressFunction): Pseudocode

create for each of = transform() Add all to

JDK List addresses = new ArrayList(); for (Person person : people) { addresses.addAll(person.getAddresses()); }

GSC MutableList addresses =

people.flatCollect(addressFunction);

Note the flatCollect method's similarity to a collect method having the same signature: each method's Function parameter maps to an Iterable type. This is optional for collect, but required of flatCollect. Both methods return a new collection. The difference is that collect in this form creates a collection of collections from a simple List, Set or Bag, while flatCollect performs a different (and in this instance, somewhat more useful) action, returning a flat list of addresses.

GroupBy pattern Create 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, which associates multiple values for each key. The Function is applied to each element and the result is used as the key into the Multimap. The elements are traversed in the same order as they would be in a ForEach pattern . groupBy(Function) Group the elements into a new Multimap. Uses the Function to get the key for each element. groupBy(Function, targetMultimap) Same as groupBy except that results are added to the specified targetMultimap. groupByEach(Function) Same as groupBy except that the Function transforms each value into multiple keys, returning a new Multimap containing all the key/value pairs.

12

GS Collections | Iteration patterns

Short-circuit patterns Methods 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 that cease execution when a specific condition is met. With each iteration, the Predicate is evaluated. If the evaluation resolves as a specified boolean (true/false) value, then iteration halts and returns the appropriate value.

Detect pattern Finds and returns the first element that satisfies a given logical expression. Detect returns the first element that satisfies a Predicate. If no true evaluation occurs, all elements in the collection are tested and the method returnsnull. Pseudocode

for each of if condition() return

JDK for (int i = 0; i < list.size(); i++) { Integer v = list.get(i); if (v.intValue() > 50) { return v; } return null; }

GSC list.detect(Predicates.greaterThan(50));

Detect methods detect(Predicate) Return the first element of the collection for which Predicate evaluates as true when given that element as an argument; if no element causes Predicate to evaluate as true, the method returns null. detectIfNone(Predicate, Function0) Same as detect, but if no element causes Predicate to evaluate as true, return the result of evaluating Function0.

AnySatisfy pattern Determine if any collection element satisfies a given logical expression. The AnySatisfy- method tests for the first occurrence of an element that the Predicate evaluates as true. If such an element is found, execution halts and the method returns true; otherwise, the it returns false. Pseudocode

for each of if condition() return true otherwise return false

JDK for (int i = 0; i < list.size(); i++) { Integer v = list.get(i); if (v.intValue() > 50)

13

GS Collections | Iteration patterns

{ return true; } } return false;

GSC return list.anySatisfy(Predicates.greaterThan(50));

AnySatisfy methods anySatisfy(Predicate) Return true if the Predicate evaluates as true for any element of the collection. Otherwise (or if the collection is empty), return false. anySatisfyWith(Predicate2, parameter) Return true if the Predicate2 evaluates as true for any element of the collection. Otherwise (or if the collection is empty), return false.

AllSatisfy pattern Determine if all collection elements satisfy a given logical expression. The AllSatisfy-pattern method determines whether all elements satisfy the Predicate; that is, it seeks the first element that evaluates as false for the given predicate. If such as element is found, execution halts and the method returns false. Otherwise, the method returns true. Pseudocode for each of if not condition() return false otherwise return true

JDK for (int i = 0; i < list.size(); i++) { Integer v = list.get(i); if (v.intValue() age; } }, 18);

In this single instance, there is no reason to write it out this longer way; the extra generality - making age the second argument 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 MutableList people =...; Predicate2 agePredicate = new Predicate2() { @Override public boolean accept(Person eachPerson, Integer age) { return eachPerson.getAge() > age; } }; MutableList drivers = people.selectWith(agePredicate, 17); MutableList voters = people.selectWith(agePredicate, 18); MutableList drinkers = people.selectWith(agePredicate, 21);

23

GS Collections | Iteration patterns

Map iteration methods Containers derived from the Map interfaces (MapIterable, MutableMap, ImmutableMap) and the Multimap interfaces (MutableListMultimap, et al.) differ from those implementing MutableList, MutableSet, and MutableBag, all of whose iteration patterns are specified by RichIterable. Maps, are a special case, comprising two separate, though joined groups of elements: a set of keys and their associated values. To enable iteration over the special structure of Maps and Multimaps, GS Collections provides a set of map-specific methods whose operations and returned objects are specific to the keys, values, and entries (combined key-value elements) that make up a Map.

Creating iterable views of maps Wrapper 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 the modifiable, non-lazy objects returned by the corresponding Java Collections Framework methods. valuesView()

(Maps and Multimaps) Returns an unmodifiable RichIterable wrapper over the values of the Map.

keysView()

(Maps and Multimaps) Returns an unmodifiable RichIterable wrapper over the keySet of the Map.

entriesView()

(Maps only) Returns an unmodifiable RichIterable wrapper over the entrySet of the Map.

ForEach Iteration These three methods call a code block for each element on a Map (all return void). forEachKey(Procedure)

Calls the Procedure on each key of the Map.

forEachValue(Procedure)

Calls the Procedure on each value of the Map.

forEachKeyValue(Procedure2)

Calls the Procedure on each key-value pair of the Map.

Collecting entries Gather 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, keySelector, valueSelector) (Maps only) The key and value for each entry is determined by applying the keySelector and valueSelector (in each case, a Function) to each item in collection. Each is converted into a key-value entry and inserted into the Map. If a new entry has the same key as an existing entry in the calling map, the new entry's value replaces that of the existing entry.

24

GS Collections | Iteration patterns

Finding, testing and putting values Detect a value by its key and, optionally, insert or return other values. The getIfAbsent… and ifPresentApply methods locate a specified key and return a map value that corresponds to that key. Depending on whether a value is found at the given key, each method performs a specific action. getIfAbsent(key, Function0) Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the result of evaluating the specified Function0 (here, specifically, a code block without parameters that returns some object). getIfAbsentPut(key, Function0) Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the result of evaluating the specified Function0, and puts that value in the map at the specified key getIfAbsentPutWith(key, Function, parameter) Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the result of evaluating the specified one-argument Function using the specified parameter, and put that value in the map at the specified key. getIfAbsentWith(key, Function, parameter) Returns the value in the Map that corresponds to the specified key; if there is no value at the key, returns the result of evaluating the specified Function and parameter. ifPresentApply(key, Function) If there is a value in the Map that corresponds to the specified key, returns the result of evaluating the specified Function with the value, otherwise returns null.

25

GS Collections | Iteration patterns

26

Chapter

2 Collections and containers Topics: • • •

Basic collection types Creating and converting collections Protecting collections

What is perhaps most distinctive about the GS Collections collection classes is what (quite properly) is hidden: their implementation of iteration patterns. Through this encapsulation, GS Collections is able to provide optimized versions of each method on each container. For example, the first of the classes we'll discuss here, FastList is array-based; it iterates using indexed access directly against its internal array. We'll begin with the GS Collections implementations of types having analogs in the Java Collections Framework (JCF). We'll then discuss the new types Bag and Multimap, the Immutable collections, and protective wrappers.

27

GS Collections | Collections and containers

Basic collection types The most commonly-used GS Collections classes are FastList, UnifiedSet, and UnifiedMap. These collections serve as drop-in replacements for their corresponding types in the Java Collections Framework (JCF). Note that these GS Collections classes do not extend the JCF implementations; they are instead new implementations of both JCF and GS Collections interfaces, as this (highly-simplified) diagram summarizes:

The methods of the JCF types are primarily focused on adding or removing elements and similar, non-iterative operations. 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.

MutableList An ordered collection that allows duplicate elements. The MutableList interface (extending ListIterable) describes a collection of elements that have a specific order, with duplicate values permitted. MutableList extends the JCF List interface and has the same contract. It also extends RichIterable which provides the iteration methods described in the previous topic, The most common implementation of MutableList is FastList, which can be used to replace the familiar java.util.ArrayList.Here is a comparison of how the two types can be created. Class

Example

ArrayList (JCF)

List comparison = new ArrayList(); comparison.add("Comcast"); comparison.add("IBM); comparison.add("Microsoft"); comparison.add("Microsoft"); return comparison;

FastList (GSC)

return FastList.newListWith("Comcast","IBM", "Microsoft", "Microsoft");

The MutableList interface includes the sortThis and reverse methods, which are similar to the static methods with the same names on java.util.Collections.Both are mutating methods. Here is an example of using sort using the JDK API and then GS Collections

28

Class

Example

ArrayList (JCF)

Collections.sort(people, new Comparator() { 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()); }

GS Collections | Collections and containers

Class

Example });

FastList (GSC)

people.sortThis(new Comparator() { 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()); } });

MutableList adds a new method called sortThisBy, which gets some attribute from each element using a Function and then sorts the list by the natural order of that attribute. Class

Example

ArrayList (JCF)

Collections.sort(people, Functions.toComparator(Person.TO_AGE));

FastList (GSC)

people.sortThisBy(Person.TO_AGE);

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.reverse();

The toReversed method on MutableList lets you reverse a list without mutating it. Here is an example of how to accomplish that in the JCF and in GS Collections. Class

Example

ArrayList (JCF)

List reversed = new ArrayList(people) Collections.reverse(reversed);

FastList (GSC)

MutableList reversed = people.toReversed();

MutableSet An unordered collection that allows no duplicate elements. The MutableSet interface (extending SetIterable) defines an unordered collection that does not permit duplicate elements. An attempt to add duplicate elements to a MutableSet container is ignored without throwing an exception. The order in which the elements are processed during iteration is not specified. MutableSet extends SetIterable and has the same contract. The most common implementation is UnifiedSet, which is the GS Collections counterpart of HashSet in the Java Collections Framework. As with MutableList, the MutableSet interface extends the RichIterable interface. Class

Example

HashSet (JDK) Set comparison = new HashSet(); comparison.add("IBM"); comparison.add("Microsoft"); comparison.add("Oracle");

29

GS Collections | Collections and containers

Class

Example comparison.add("Comcast"); return comparison;

UnifiedSet (GSC) return UnifiedSet.newSetWith("IBM", "Microsoft", "Verizon", "Comcast");

MutableMap A collection of key/value pairs The MutableMap interface defines an association of key/value pairs. It extends the MapIterable interface, which furnishes a set of iteration methods especially for the key/value structure of a Map collection. These include unmodifiable 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 map = new HashMap(); map.put(1, "1"); map.put(2, "2"); map.put(3, "3");

UnifiedMap (GSC)

MutableMap map = UnifiedMap.newWithKeysValues(1, "1", 2, "2", 3, "3");

MutableBag An unordered collection that allows duplicates. A MutableBag (extending Bag) combines the less-restrictive aspects of a Set - in that it is an unordered collection - and a List, which permits adding duplicate values. It is implemented using a specialized kind of map, called a multiset, which pairs each distinct value as a key with the count of its occurrences in the collection as a value. For example, this list:

Apple Pear Orange Orange Apple Orange

could create this bag:

Pear

1

Orange

3

Apple

2

GSC return MutableBag < String > bag = HashBag.newBagWith("Apple", "Pear", "Orange", "Apple", "Apple", "Orange");

30

GS Collections | Collections and containers

The MutableBag interface includes methods for getting and manipulating the number of occurrences of an item. For example, to determine the number of unique elements in a MutableBag, use the sizeDistinct() method.

Multimap A 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, but one whose values consist of individual collections of a specified type, called the backing collection. A Multimap is useful in situations where you would otherwise use Map. Unlike the other basic GS Collections containers, Multimap does not extend RichIterable, but resides along with its subinterfaces 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, the FastListMultimap class is backed by a UnifiedMap that associates each key with a FastList that preserves the order in 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 by their length, obtaining a Multimap with integer (word=length) keys and lists of words having that length for values. This simple list:

here

key value

produces a List-backed Multimap:

are

1

a

a

3

are,few,are,not,too

few

4

here,that,long

words

5

words

that are not too long The code that performs this action uses the groupBy method. GSC MutableList words = FastList.newListWith("here", "are", "a", "few", "words", "that", "are", "not", "too", "long"); MutableListMultimap multimap = words.groupBy(StringFunctions.length());

The interface MutableListMultimap extends the Multimap interface and tells us the type of its backing collections. Since this example uses Lists, the word "are" is allowed to occur twice in the list at key 3. If we use groupBy on the same source list to generate a Multimap of Sets, the resulting backing collections will eliminate duplicate entries and disregard the order of elements in the source List: GSC MutableSetMultimap multimap = words.groupBy(StringFunctions.length());

With duplicates removed, only four 3-letter words remain.

key

value

1

a

31

GS Collections | Collections and containers

3

too,are,few,not,

4

long,here,that

5

words

Creating and converting collections The following methods can be used to convert one container type to another. All of these methods are on RichIterable. To create immutable and fixed-size collections, refer to Immutable collections. toList()

Converts the collection to the default MutableList implementation (FastList).

toSet()

Converts the collection to the default MutableSet implementation (UnifiedSet).

toBag()

Converts the collection to the default MutableBag implementation (HashBag).

toMap(keySelector, valueSelector)

Converts the collection to the default MutableMap implementation (UnifiedMap) using the specified keySelectors and valueSelectors.

toSortedList()

Converts the collection to the default MutableList implementation (FastList) and sorts it using the natural order of the elements.

toSortedList(Comparator)

Converts the collection to the default MutableList implementation (FastList) and sorts it using the specified 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()

Creates a new, empty, and mutable container of the same collection type. For example, if this instance is a FastList, this method will return a new empty FastList. If the class of this instance is immutable (see below) or fixed size (for example, a singleton List) then a mutable alternative to the class is returned.

Protecting collections GS 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. Synchronized collection: a wrapper that presents a mostly thread-safe view of a collection.

Immutable collections A 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 references and data throughout its lifespan. An immutable collection is equal to a corresponding mutable collection with the same contents; a MutableList and an ImmutableList can be equal.

32

GS Collections | Collections and containers

Because its state does not change over time, an immutable collection is always thread-safe. Using immutable collections 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 respective types. 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

The method that returns an immutable collection for all container types is: MutableCollection.toImmutable()

Returns an immutable copy of a type corresponding to the source MutableCollection.

An immutable-collection interface lacks mutating methods, such as add() and remove(). Instead, immutable collections have methods that return new, immutable copies with or without specified elements: ImmutableCollection.newWith(element)

Returns a new immutable copy of ImmutableCollection with element added.

ImmutableCollection.newWithAll(Iterable)

Returns a new immutable copy of ImmutableCollection with the elements of Iterable added.

ImmutableCollection.newWithout(element)

Returns a new immutable copy of ImmutableCollection with element removed.

ImmutableCollection.newWithoutAll(Iterable)

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 new, immutable collections. Immutable Collection Factory Classes The factory classes Lists, Sets, Bags, and Maps create immutable collections. These factories also provide methods for creating fixed-size collections, which have been superseded by immutable collections. ImmutableList immutableList = Lists.immutable.of(1, 2, 3); ImmutableSet immutableSet = Sets.immutable.of(1, 2, 3); Bag immutableBag = Bags.immutable.of(1, 2, 2, 3); ImmutableMap 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 are sized according to their contents. In cases where there are many, even millions of collections, each with a size less than 10, this is an important advantage.

33

GS Collections | Collections and containers

Protective wrappers Wrapper 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 by means of the asUnmodifiable method, which returns a read-only view of the calling collection. This means that the mutating methods of the collection (e.g., add, remove) are still present, but throw exceptions if called. MutableCollection.asUnmodifiable()

Returns a read-only view of the source collection.

Synchronized Collections GS Collections provides a wrapper for rendering a modifiable but thread-safe view that holds a lock when a method is called and releases the lock upon completion. MutableCollection.asSynchronized()

34

Returns a synchronized copy of the source collection.

Chapter

3 Code blocks Topics: •

Common code block types

A code block, in GS Collections terms, is a single-abstract-method object that is passed as a parameter to an iteration method. It is an abstraction that represents the evaluation of each element in the course of iteration. It helps us to further separate what is being done from how it's done. This topic enumerates the basic code block types - the GS Collections interfaces and classes - and the relevant methods to which they apply. What we call a "code block" in GS Collections is roughly analogous to what is more formally and precisely termed a closure or first-class function. A closure is a function that, when passed to a method, can access and modify variables in its enclosing scope. This is a facility that the Java language does not (as of this writing) support. The closest analog to a closure in Java is the anonymous inner class (which allows read access to local final variables), and this is one technique among several for implementing code blocks in GS Collections. In this inline example, the highlighted text is a nameless code block, used as predicate (a yes/no function used as a filter) that implements a Predicate interface. This code block is passed as the parameter of a select method call. A Predicate has one method of its own, accept(), which takes as its sole argument each, the current element upon each iteration of the enclosing select method. GSC MutableList texans = this.people.select(new Predicate() { public boolean accept(Person each) { return each.getAddress().getState().equals("TX"); } }); Verify.assertSize(1, texans);

In this case, if the value of state field for any element in people equals "TX" then the select method adds that element to the new list, texans. About parameter and argument: These terms are often (if inaccurately) used interchangeably to refer to method or function inputs. (The usual distinction holds that parameter refers to 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 this topic - we use parameter to specify the input to an iteration method - in this example, select. These parameters can take the form of the code block (as described in this topic), which itself is an object with methods. The input for a code block we refer to here as the argument - in this example, the argument is each (the "current element" upon each iteration).

35

GS Collections | Code blocks

Common code block types Here is a summary of the most commonly-used code blocks and the GS Collections methods that use them. Arguments

Returns

Used By

Predicate Evaluates each element of a collection (the argument), and returns a boolean value.

One (T)

boolean

select, reject, detect, anySatisfy, allSatisfy, count

Predicate2

Two (T,P)

boolean

selectWith,rejectWith, detectWith, anySatisfyWith,allSatisfyWith, countWith

Function (transformer): Evaluates each element of a collection as the argument to the code block logic and returns a computed value

One (T)

Object (V)

collect,flatCollect, groupBy

Function2

Two (T,P)

Object (V)

forEachEntry() injectInto() collectWith()

Function3

Three (T,P,?)

Object (V)

injectIntoWith

Procedure : Executes on each element of a collection, returns nothing.

One (T)

void

forEach, forEachKey, forEachValue,

Procedure2

Two (T,P)

void

forEachWith, forEachKeyValue

Function0 : Executes and returns a value (like Callable); represents deferred evaluation.

Zero

Object (V)

getIfAbsent, getIfAbsentPut, ifPresentApply

Comparator: "Imposes a total ordering on some collection of objects." (JDK)

Two (T,T)

int (negative, 0, positive) sortThis, max, min

Predicate A Predicate is a single-argument code block that evaluates an element and returns a boolean value. Also known as a discriminator or filter, it is used with the filtering methods select, reject, detect, anySatisfy, allSatisfy, and count. The accept method is implemented to indicate the object passed to the method meets the criteria of this Predicate. Predicate Factories

36

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."

StringPredicates

Supports empty, notEmpty, contains, isAlpha, isNumeric, isBlank, startsWith, endsWith, matches, etc.

GS Collections | Code blocks

Predicate Factories IntegerPredicates

Supports isEven, isOdd, isPositive, isNegative, isZero .

LongPredicates

Supports isEven, isOdd, isPositive, isNegative, isZero.

Predicates factory The Predicates class can be used to build common Predicates (predicates) to be used with filtering patterns. Predicates supports equals, not equals, less than, greater than, less than or equal to, greater than or equal to, in, not in, and, or, and numerous other predicate-type operations. Some examples with select(): GSC MutableList myList =... MutableList selected1 = myList.select(Predicates.greaterThan(50));

Function The Function code block in its most common usage takes each element of a collection as the argument to the codeblock logic. It selects an attribute from the element via a "getter" - its valueOf() method. It then returns a computed value or, if no evaluation logic is performed, the attribute itself. 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 a transformed 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.

Function Factories Functions (static class)

getToClass()

getToString()

getPassThru()

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 with guidance).

Procedure A Procedure is a code block that performs an evaluation on its single argument and returns nothing. A Procedure is most commonly used with ForEach -pattern methods. Count and calculate CountProcedure

Apply a Predicate to an object and increment a count if it returns true.

37

GS Collections | Code blocks

CounterProcedure

Wrap a specified block and keeps track of the number of times it is executed.

SplitDoubleSumProcedure

Create two double sums, one for items that return true for the specified discriminator and one for items that return false. A DoubleSelector must be provided.

SplitIntegerSumProcedure

Create two integer sums, one for items that return true for the specified discriminator and one for items that return false. An IntegerSelector must be provided.

SumProcedure

Summarize the elements of a collection either via a forEach() or injectInto() call. SumProcedure returns optimized primitive blocks for specialized primitive subclasses of Function which result in less garbage created for summing primitive attributes of collections.

Return a value ResultProcedure

Store a result to be accessed after an iteration is complete; this is useful for determining a return value from a forEach() invocation, which itself has no return value.

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 a single 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 case statement, the corresponding block will be executed.

IfProcedure

Evaluate the specified block only when either discriminator returns true. If the result of evaluating the Predicate is false, and the developer has specified that there is an elseProcedure, then the elseProcedure is evaluated.

IfProcedureWithInt

Apply an index that effectively filters which objects should be used.

Modify collections and maps

38

CollectionAddProcedure

Add elements to the specified collection when block methods are called.

CollectionRemoveProcedure

Remove element from the specified collection when block methods are called.

ConcurrentMapOfListsPutProcedure

Use a specified Function to calculate a key for an object passed to the value method. The object is put into a MultiReaderFastList contained in the specified Map at the position of the calculated key.

MapPutProcedure

Use a specified Function to calculate the key for an object and puts the object into the specified Map at the position of the calculated key.

MultimapPutProcedure

Use a specified Function to calculate the key for an object and puts the object with the key into the specified MutableMultimap.

StringBufferProcedure

Transform to string and append elements of a collection to a StringBuffer, separated by the specified separator after trans.

StringBuilderProcedure

Transform to string and append elements of a collection to a StringBuider, separated by the specified separator.

GS Collections | Code blocks

Output a collection to a system PrintlnProcedure

Outputs an object to a PrintSteam using println.

39

GS Collections | Code blocks

40

Chapter

4 Utility GS Collections Topics: • •

Utility iteration patterns Parallel iteration

GS Collections includes an assortment of static utility classes, such as Iterate and ListIterate, that provide interoperability of GS Collections iteration methods with standard Java collection classes. Class

Used with

Iterate

Iterables (inclusive Collections)

ListIterate

List

MapIterate

Maps

ArrayIterate

Arrays

StringIterate

Strings

ParallellIterate

Parallel processing

41

GS Collections | Utility GS Collections

Utility iteration patterns Pattern For Each

Implementation JDK for (int i = 0; i < list.size(); i++) { this.doSomething(list.get(i)); }

Utility GSC Iterate.forEach(collection, new Procedure() { public void value(Object each) { doSomething(each); } });

Collect

JDK List addresses = new ArrayList(); for (Person person : people) { addresses.add(person.getAddress()); }

Utility GSC Iterate.collect(collection, Function.TO_STRING_SELECTOR);

Select

JDK List greaterThanFifty = new ArrayList(); for (Integer each : list) { if (each.intValue() > 50) { greaterThanFifty.add(each); } }

Utility GSC Iterate.select(collection, Predicates.greaterThan(new Integer(50)));

Reject

JDK List notGreaterThanFifty = new ArrayList(); for (Integer each : list) { if (each 50) { return v; } return null; }

Utility GSC Iterate.detect(collection, Predicates.greaterThan(new Integer(50)));

Any Satisfy

JDK for (int i = 0; i < list.size(); i++) { Integer v = list.get(i); if (v.intValue() > 50) { return true; } } return false;

Utility GSC Iterate.anySatisfy(collection, Predicates.greaterThan(new Integer(50)));

All Satisfy

JDK for (int i = 0; i < list.size(); i++) { Integer v = list.get(i); if (v.intValue()