gs collections training session and kata (handouts … ntro what is a code kata? •a programming...

240
GS Collections Code Kata August 2012 Copyright © 2012 Goldman Sachs. All rights reserved.

Upload: lamminh

Post on 26-Mar-2018

214 views

Category:

Documents


1 download

TRANSCRIPT

GS Collections

Code Kata August 2012

Copyright © 2012 Goldman Sachs. All rights reserved.

INTRO

10 Second Intro

What is GS Collections?

A Java Collections Library.

What is a Code Kata?

A programming exercise which helps hone your skills through practice.

2

Presenter
Presentation Notes
From Wikipedia: Code Kata is a term coined by Dave Thomas, co-author of the book The Pragmatic Programmer, in a bow to the Japanese concept of kata in the martial arts. A code kata is an exercise in programming which helps a programmer hone their skills through practice and repetition.

INTRO

What is GS Collections?

• A supplement or replacement for the Java Collections Framework (JCF).

• Developed at Goldman Sachs.

• "Inspired by" Smalltalk Collection protocol.

3

Presenter
Presentation Notes
Who has used Smalltalk? "Inspired by" means: It uses the same method names and implements a similar API but it interoperates with Java and had grown and evolved over six+ years (since late 2005)

INTRO

What is a Code Kata?

• A programming exercise which helps hone your skills through practice.

• This one is set up as a series of unit tests which fail.

• Your task is to make them pass, using GS Collections –

I hear and I forget.

I see and I remember.

I do and I understand.

- Confucius

GS Collections Code Kata

• New concepts are introduced in the slides.

• Coding exercises are at the end of each section.

4

ITERATION PATTERNS

5

ITERATIO

N PA

TTERNS

Sort

• What is an iteration pattern?

• Sort is one example.

• We want to sort a list of people by last name, first name.

• Which method in the JCF can we use?

Domain

Person john = new Person("John", "Smith"); Person jane = new Person("Jane", "Smith"); Person z = new Person("Z.", "Jones"); List<Person> people = new ArrayList<Person>(); people.add(john); people.add(jane); people.add(z);

6

ITERATIO

N PA

TTERNS

Javadoc

public static void java.util.Collections.sort( List<T> list, Comparator<? super T> c)

Sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable.

Anonymous inner class syntax

JCF example

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

7

Presenter
Presentation Notes
This example uses the anonymous inner class syntax. Make sure you understand it before moving on. The arrow is a link to the appendix which has more information about anonymous inner classes.

ITERATIO

N PA

TTERNS

Javadoc

public static void java.util.Collections.sort( List<T> list, Comparator<? super T> c)

Sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable.

Does anything bother you about Collections.sort()?

8

ITERATIO

N PA

TTERNS

Javadoc

public static void java.util.Collections.sort( List<T> list, Comparator<? super T> c)

Sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable.

Does anything bother you about Collections.sort()?

JCF problems

• Why isn’t sort() a method on every List?

Collections.sort(list, comparator); vs.

list.sort(comparator);

9

Presenter
Presentation Notes
Collections.sort() only takes a List, not a Collection. Such a specific type signature suggests that this method is misplaced.

ITERATIO

N PA

TTERNS

Javadoc

public static void java.util.Collections.sort( List<T> list, Comparator<? super T> c)

Sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable.

Does anything bother you about Collections.sort()?

JCF problems

• Where are all the iteration patterns?

• java.util.Collections provides methods for sort(), min(), max() and just a few others.

• The most common iteration patterns are missing:

• Collect a list of each person’s address.

• Select only those people whose age is 18 or higher.

10

Presenter
Presentation Notes
Rather than define the term “iteration patterns” we just show them through examples.

ITERATIO

N PA

TTERNS

Iteration Patterns

• We want the methods sort(), min(), max(), collect(), select(), etc. on every collection.

• How can we accomplish this in code?

11

ITERATIO

N PA

TTERNS

Iteration Patterns

• We want the methods sort(), min(), max(), collect(), select(), etc. on every collection.

• How can we accomplish this in code?

• Create interfaces that extend the JCF interfaces.

GS Collections Interfaces

public interface MutableList<T> extends List<T> { MutableList<T> sortThis(Comparator<? super T> comparator); MutableList<T> select(Predicate<? super T> Predicate); ... }

12

ITERATIO

N PA

TTERNS

Inheritance Hierarchy

• MutableList extends List.

• FastList is a drop-in replacement for ArrayList.

• FastList could extend ArrayList, but we chose not to.

• Iteration patterns were pulled up higher into RichIterable.

13

Lists

Presenter
Presentation Notes
We chose not to extend ArrayList when implementing FastList mainly for efficiency reasons.

ITERATIO

N PA

TTERNS

Inheritance Hierarchy Sets

• MutableSet extends Set.

• UnifiedSet is a drop in replacement for HashSet.

• Everything about Lists is analogous for Sets (and Bags).

• This is why iteration patterns were pulled up higher into RichIterable –

• min() for example is identical across collection types.

14

Presenter
Presentation Notes
Also, iteration patterns were pulled up into RichIterable because there are other classes that implement RichIterable yet aren’t java.util.Collections. Interval is one example. It represents a range of numbers. We can iterate over an Interval, but we can’t add to it, so it cannot be a Collection.

ITERATIO

N PA

TTERNS

Inheritance Hierarchy

Maps

• MutableMap extends Map.

• UnifiedMap is a drop in replacement for HashMap.

15

ITERATIO

N PA

TTERNS

Examples

Collect Returns a new collection where each element has been transformed.

Select Returns the elements of a collection that satisfy some condition.

Code Blocks

• sortThis() takes a Comparator, which is a strategy interface.

• Similarly, collect() and select() take “code block” parameters.

• collect() takes a Function.

• select() takes a Predicate.

• Don’t get hung up on these names because the IDE will remind you.

16

COLLECT PATTERN

17

CO

LLECT PA

TTERN Iteration Pattern

• Collect pattern (aka map or transform).

• Returns a new collection where each element has been transformed

• e.g. collect each person’s address.

• Function is the type that takes an object and returns an object of a different type

• aka Transformer

GS Collections Example

List<Person> people = ...

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

18

CO

LLECT PA

TTERN Iteration Pattern

• Function is the type that takes an object and returns another type.

GS Collections Example

MutableList<Person> people = ...

MutableList<Address> addresses = people.collect( new Function<Person, Address>() { public Address valueOf(Person person) { return person.getAddress(); } }); 19

Presenter
Presentation Notes
This is the first example using anonymous inner class syntax with GS Collections. We don’t have anonymous lambdas in Java so we have to give names to every combinations of types. Function just means some type to some other type. Predicate means some type to boolean.

CO

LLECT PA

TTERN Iteration Pattern

• The loop moves in to the implementation of collect().

• Let’s look at a realistic implementation of collect() for FastList.

GS Collections Example

public <V> MutableList<V> collect( Function<? super T, ? extends V> function) { MutableList<V> result = FastList.newList(this.size); for (int i = 0; i < this.size; i++) { result.add(function.valueOf(this.items[i])); } return result; }

20

Presenter
Presentation Notes
The Function’s valueOf() method is called once per item in the items array.

SELECT PATTERN

21

SELECT P

ATTERN

Iteration Pattern

• Select pattern (aka filter).

• Returns the elements of a collection that satisfy some condition

• e.g. select only those people whose age is 18 or higher.

• Predicate is the type that takes an object and returns a boolean.

GS Collections Example

MutableList<Person> people = ...

MutableList<Person> adults = people.select( new Predicate<Person>() { public boolean accept(Person each) { return each.getAge() >= 18; } }); 22

Presenter
Presentation Notes
We don’t have anonymous lambdas in Java so we have to give names to every combination of types. Predicate just means to convert some type to boolean.

KATA INTRODUCTION

23

KA

TA INTRO

DU

CTION

Domain

• GS Collections Kata uses LineItems, Companies, Orders, Customers, and Suppliers.

• Our tests extend CompanyDomainForKata, which sets up some customers, suppliers and orders for a company.

• Data is available to you through getters on this.company • For example this.company.getCustomers();

Hints

• Most changes will be under src/test.

• Some changes will be under src/main.

• Feel free to refactor the domain under src/main.

• Pay close attention to the Javadoc for instructions and hints.

• Use the IDE support for Javadoc @links.

24

KATA EXERCISE 1

25

KA

TA Exercise 1

• Find Exercise1Test; it has assertion failures if you run it as a test.

• Figure out how to get the tests to pass using what you have seen so far.

• Should take about 15 minutes.

26

KA

TA Solution 1

public void getCustomerNames() {

MutableList<Customer> customers = this.company.getCustomers(); MutableList<String> customerNames = customers.collect(nameFunction); ... Assert.assertEquals(expectedNames, customerNames); }

27

Presenter
Presentation Notes
<solution>

KA

TA Solution 1

public void getCustomerCities() { MutableList<String> customerCities = customers.collect( new Function<Customer, String>() { public String valueOf(Customer customer) { return customer.getCity(); } }); ... Assert.assertEquals(expectedCities, customerCities); }

28

Presenter
Presentation Notes
You can fill in the definition of valueOf() inside the anonymous inner class using IDE shortcuts. IntelliJ’s ctrl+I is implement interface. Eclipse’s ctrl+1 is auto-fix and works to implement interfaces. <solution>

KA

TA Solution 1

public void getLondonCustomers() {

... MutableList<Customer> customersFromLondon = customers.select(new Predicate<Customer>() { public boolean accept(Customer customer) { return customer.getCity().equals("London"); } }); Verify.assertSize(2, customersFromLondon); }

29

Presenter
Presentation Notes
This is the first appearance of “Verify” so we’ll go over it in the next section. <solution>

TESTUTILS

30

TESTU

TILS Verify

•GS Collections distribution includes collections-testutils.jar.

• Includes helpful utility for writing unit tests.

•Collection-specific.

• Implemented as an extension of JUnit.

•Most important class is called Verify.

Code Example

Example from the previous solution

Verify.assertSize(2, customersFromLondon); Instead of

Assert.assertEquals(2, customersFromLondon.size());

31

TESTU

TILS Verify

Several other self-explanatory examples:

Code Example

Verify.assertNotEquals(1, 2); Verify.assertEmpty(FastList.newList()); Verify.assertNotEmpty(FastList.newListWith(1)); Verify.assertContains(1, FastList.newListWith(1));

32

Presenter
Presentation Notes
And this is the first slide with the various ways to construct a FastList. We cover that in more depth later.

TESTU

TILS GS Collections Testutils

•It’s possible to go too far.

•The first form is more verbose.

•The second form asserts more because of the contract of equals().

Bad

Verify.assertSize(3, list); Verify.assertContainsAll(list, 1, 2, 3);

Good

Assert.assertEquals( FastList.newListWith(1, 2, 3), list);

33

Presenter
Presentation Notes
You should favor assertEquals which will use the underlying equals() method. This will include ordering, type checking etc.

QU

ESTION

S

34

Presenter
Presentation Notes
<solution>

BENEFITS OF GS COLLECTIONS

35

BEN

EFITS OF G

S CO

LLECTION

S Pros

• Increased readability.

• Reduced duplication – less to test.

• Simplified iteration.

• Optimized by type for memory and speed.

Cons

•No lambdas or closures – anonymous inner class syntax.

36

BEN

EFITS OF G

S CO

LLECTION

S Readability

• Object-oriented programming is a paradigm that groups data with the methods that predicates on the data.

• Functional programming is a paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data.

• Possible to merge the two paradigms and wind up with very readable code.

• Where they sometimes clash is mutable state.

37

Presenter
Presentation Notes
Note: Smalltalk combined OO and functional in 1980

BEN

EFITS OF G

S CO

LLECTION

S Example

x = 5

x = 6

Imperative Programming

• In Java this is OK.

• The value of x changes over time.

Math

• In pure math this makes no sense.

• The value of x is 5, it cannot be reassigned.

38

Presenter
Presentation Notes
Similar with sets. A set is defined to contain some elements. It makes no sense to “add an item to a set.” You can either take a union or define a new set based on the definition of a previous set.

BEN

EFITS OF G

S CO

LLECTION

S Imperative Programming

• In imperative programming, time is important.

• The truth of conditions changes with the state of the program.

• This can decrease readability.

• can be difficult to reason about.

• can be difficult to test.

• Think architecture that is concurrent and based on asynchronous callbacks.

Code Example

List<Person> people = ...

List<Address> addresses = new ArrayList<Address>(); // Not true yet! It’s an empty list, not a list of addresses!

for (Person person : people) { addresses.add(person.getAddress()); }

39

BEN

EFITS OF G

S CO

LLECTION

S Imperative vs. Functional

• fibonacci() function returns the same output for the same input.

• We can tell it doesn’t use mutable state; it can be static.

• Iterators are not functional.

• next() takes no input, yet returns different values over time.

• It obviously uses internal state.

Code Example

for (int i = 0; i < 10; i++) { System.out.println(this.fibonacci(i)); } // vs. for (int i = 0; i < 10; i++) { System.out.println(this.fibonacciIterator.next()); }

40

BEN

EFITS OF G

S CO

LLECTION

S Benefits

• Iteration patterns are methods on our collections.

• Simply naming the patterns enhances readability:

people.collect(...)

Drawbacks

• These methods take a parameter which is a bit of code:

• how to collect or select.

• The thing inside the parentheses is now less readable:

• represented as an anonymous inner class.

41

BEN

EFITS OF G

S CO

LLECTION

S Readability

• Ideally, Java would have native support for anonymous functions (aka lambda expressions, erroneously aka closures).

• The syntax below works with an early prototype of Java 8 (we tested).

JDK 8 Prototype

MutableList<Person> people = ...; MutableList<Address> addresses = people.collect( person -> person.getAddress()); MutableList<Address> addresses = people.collect(Person::getAddress);

42

Presenter
Presentation Notes
Syntax subject to change at the disgression of Oracle / the expert group.

BEN

EFITS OF G

S CO

LLECTION

S Readability

• Often you need to write out a Function.

• It makes sense to hide the boilerplate code on the domain object.

Collect with hidden Function

MutableList<Person> people = ...; MutableList<Address> addresses = people.collect(Person.TO_ADDRESS);

Function on domain Object

public class Person { public static final Function<Person, Address> TO_ADDRESS = new Function<Person, Address>() { public Address valueOf(Person person) { return person.getAddress(); } }; ... }

43

Presenter
Presentation Notes
Compare this syntax with the Java 8 syntax from the last slide. They wind up looking very similar.

BEN

EFITS OF G

S CO

LLECTION

S Readability

Encapsulating the Function looks very similar to the proposed lambda syntax.

Encapsulated Function

MutableList<Person> people = ...; MutableList<Address> addresses = people.collect(Person.TO_ADDRESS);

JDK 8 Prototype

MutableList<Person> people = ...; MutableList<Address> addresses =

people.collect(Person::getAddress);

44

Presenter
Presentation Notes
The JDK 8 syntax works with GS Collections due to automatic lambda conversion for any classes with a “single abstract method”. Function is such a SAM, so this code will work without the TO_ADDRESS constant being defined. Thus, the method handle Person::getAddress will automatically be converted to an instance of Function.

BEN

EFITS OF G

S CO

LLECTION

S Readability

• We have other tricks for dealing with boilerplate code.

• GS Collections provides several “lambda factories,” like Predicates.

GS Collections Select with Predicates Factory

MutableList<Integer> mutableList = FastList.newListWith(25, 50, 75, 100); MutableList<Integer> selected = mutableList.select(Predicates.greaterThan(50));

45

Presenter
Presentation Notes
There’s also Predicates2 and Functions, etc. Type into your IDE “Predicates.” and press ctrl+space to have a look at more methods available on this and the other lambda factories. Only a few of them are covered in the Kata.

BEN

EFITS OF G

S CO

LLECTION

S Iteration Pattern

• Predicates also lets you create common Predicates from Functions.

• Combines well with the previous tip.

GS Collections Select with Predicates Factory

MutableList<Person> people = ...; MutableList<Person> theSmiths = people.select( Predicates.attributeEqual(Person.LAST_NAME, "Smith"));

46

KATA EXERCISE 2

47

KA

TA Exercise 2

• Fix Exercise2Test. • Solve the same questions as Exercise1Test. • Use the tips to make your answers as readable as possible.

• From now on, you’ll have to access the domain objects on your own.

• Start with this.company.getSomething().

• Should take about 15 minutes.

48

KA

TA Solution 2

public class Customer {

public static final Function<Customer, String> TO_NAME = new Function<Customer, String>() { public String valueOf(Customer customer) { return customer.getName(); } }; ... }

49

Presenter
Presentation Notes
<solution>

KA

TA Solution 2

public void getCustomerCities() {

MutableList<String> customerCities = this.company.getCustomers().collect(Customer.TO_CITY);

... Assert.assertEquals(expectedCities, customerCities); }

50

Presenter
Presentation Notes
<solution>

KA

TA Solution 2

public class Customer {

... public static final Function<Customer, String> TO_CITY = new Function<Customer, String>() { public String valueOf(Customer customer) { return customer.getCity(); } }; ... }

51

Presenter
Presentation Notes
<solution>

KA

TA Solution 2

public void getLondonCustomers() {

MutableList<Customer> customersFromLondon = this.company.getCustomers().select( Predicates.attributeEqual( Customer.TO_CITY, "London")); Verify.assertSize(2, customersFromLondon); }

52

Presenter
Presentation Notes
<solution>

QU

ESTION

S

53

Presenter
Presentation Notes
<solution>

IMMUTABILITY

54

IMM

UTA

BILITY Pros

Why would we prefer immutable data structures?

Cons

Why wouldn’t we prefer immutable data structures?

55

IMM

UTA

BILITY Pros

• Easier to reason about because they do not have complex state spaces that change over time.

• Can pass them around freely without making defensive copies.

• No way to corrupt through concurrent access.

• They make safe hash-table keys.

• If an object is mutated after it is placed into a HashSet, for example, that object may not be found the next time you look into the HashSet.

Cons

• They sometimes require that a large object graph be copied where otherwise an update could be done in place.

• As a result, it is common for libraries to provide mutable alternatives to immutable classes.

• For example, StringBuilder is a mutable alternative to String.

56

IMM

UTA

BILITY Class Diagram

Iterable

iterator()

RichIterable

select()

collect()

detect()

...

MutableCollection

add()

remove()

MutableList

get(int)

MutableSet

ImmutableCollection

newWith()

newWithout()

ImmutableList

ImmutableSet

57

Presenter
Presentation Notes
RichIterable is at the root of the hierarchy. All of the iteration patterns such as select(), collect(), detect(), etc. are on RichIterable. Conceptually, RichIterable is something that can be iterated over, plus the patterns that can be implemented in terms of iteration. That means all iteration patterns can be implemented in terms of the iterator() method and the parameters to the method and nothing else. RichIterable has no mutating methods, but it does have mutable subclasses. We call this a readable interface. It has sub-interfaces. MutableCollection has the methods add() and remove() and is the root of all mutable collections. ImmutableCollection doesn't have any mutating methods, but it has methods to return new immutable collections containing additional elements. JDK: Iterable 1.0: MutableCollection, MutableList, MutableSet 2.0: ImmutableCollection, ImmutableList, ImmutableSet 3.0: RichIterable

IMM

UTA

BILITY Class Diagram

RichIterable

toList() / toSet()/ toBag()

toSortedList() / toSortedSet()

groupBy()

MutableCollection

toImmutable()

ImmutableCollection

58

IMM

UTA

BILITY Conversion Methods

toList(), toSortedList(), toSet(), toSortedSet(), toBag() • Return mutable copies.

• Return new copy even when called on a collection of the same type.

Code Example

MutableList<Integer> list = FastList.newListWith(3, 1, 2, 2, 1); MutableList<Integer> noDupes = list.toSet().toSortedList(); Assert.assertEquals( FastList.newListWith(1, 2, 3), noDupes);

59

Presenter
Presentation Notes
This code example demonstrates two of the conversion methods. We start with a list of 3, 1, 2, 2, 1. The next expression chains calls to two conversion methods. First the list is converted to a set (which eliminates duplicates but also loses ordering). Then the set is converted to a sorted list. The elements of the collection need to be Comparable or toSortedList() will throw an exception. There is an overloaded form of toSortedList() which takes a Comparator as an argument in order to control sorting and it works with any type (not just Comparables). toBag() returns Bags which will be covered later groupBy() returns Multimaps which will be covered later

IMM

UTA

BILITY Overview

• ImmutableCollection interface does not extend Collection:

• No mutating methods.

• Mutating requires a new copy.

• GS Collections also has “memory-efficient” collections but they are largely superseded by ImmutableCollections.

Truly Immutable

ImmutableList<Integer> immutableList = FastList.newListWith(1, 2, 3).toImmutable(); ImmutableList<Integer> immutableList2 = Lists.immutable.of(1, 2, 3); Verify.assertInstanceOf( ImmutableTripletonList.class, immutableList); 60

Presenter
Presentation Notes
The code example shows two ways to construct immutable lists. If you do want a mutable collection, you'd need a copy. In this case, you'd use the toList() method, covered earlier, to get the mutable copy. The last line in the code example shows that the type of the list is ImmutableTripletonList. This is a special type containing exactly 3 fields, the three elements in the list. It has no backing array. This is very efficient in terms of memory. It's impossible to implement using less memory. There are a bunch of these small immutable collection classes, but at some point we do switch over to an array backed implementation.

IMM

UTA

BILITY Equality

Should a mutable list equal an immutable list?

Code Example

MutableList<Integer> mutable = FastList.newListWith(1, 2, 3); ImmutableList<Integer> immutable = Lists.immutable.of(1, 2, 3); mutable.equals(immutable);

61

IMM

UTA

BILITY Equality

Should a list and a set be equal?

Code Example

MutableList<Integer> list = FastList.newListWith(1, 2, 3); MutableSet<Integer> set = UnifiedSet.newSetWith(1, 2, 3); list.equals(set);

62

Presenter
Presentation Notes
Taking a step back a bit, should a list and a set be equal? Obviously not. A List has a specific order which is important and Sets have no order.

IMM

UTA

BILITY Equality

Should a mutable list equal an immutable list?

A list is a List because it allows duplicates and preserves order, so yes.

Code Example

MutableList<Integer> mutable = FastList.newListWith(1, 2, 3); ImmutableList<Integer> immutable = Lists.immutable.of(1, 2, 3); Assert.assertEquals(mutable, immutable);

63

Presenter
Presentation Notes
There’s nothing in the equality contract about mutability. So immutable lists equal mutable lists, immutable sets equal mutable sets, etc.

IMM

UTA

BILITY Equality

Here’s the implementation of ArrayList.equals(), really on AbstractList:

public boolean equals(Object o) { if (o == this) return true;

if (!(o instanceof List)) return false; ListIterator<E> e1 = this.listIterator(); ListIterator e2 = ((List) o).listIterator(); while (e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); if (!(o1 == null ? o2 == null : o1.equals(o2))) { return false; } } return !(e1.hasNext() || e2.hasNext()); } 64

Presenter
Presentation Notes
So, in order to get MutableLists to equal ImmtuableLists, we need ImmutableList implementations to be List! We don’t want ImmtuableList to be a List! It shouldn’t implement add()

IMM

UTA

BILITY Inheritance diagram

65

IMM

UTA

BILITY Overview

• Implementations are Collections in order to satisfy the existing contract of equals() on List and Set.

• Can be cast to Collection.

• Brings back the mutating methods.

• Brings back the UnsupportedOperationExceptions.

• Convenient for interop.

Effectively Immutable

List<Integer> list = immutableList.castToList();

Verify.assertThrows(

UnsupportedOperationException.class,

new Runnable() {

public void run() {

list.add(4);

}

}); 66

Presenter
Presentation Notes
Even though the Immutable interfaces don't extend java.util.Collection, the implementations do, and hence they can be cast. The code example casts an ImmutableList to a java.util.List. This brings back the mutating methods. When add() is called, an UnsupportedOperationException is thrown. We wouldn't have done this, but it was necessary in order to implement equals() properly. We want a list to be equal to another list regardless of whether it is mutable. Since all mutable lists check if the other object is a java.util.List in their implementations of equals(), we had to make our implementations of ImmutableList also implement java.util.List. This is unfortunate, but it does provide a level of interoperability with the JCF we wouldn't have had otherwise.

MORE ITERATION PATTERNS

67

ITERATIO

N PA

TTERNS

Other patterns that use Predicate

Short-circuit patterns that use Predicate

68

Select Returns the elements of a collection that satisfy the Predicate.

Reject Returns the elements of a collection that do not satisfy the Predicate.

Count Returns the number of elements that satisfy the Predicate.

Detect Finds the first element that satisfies the Predicate.

Any Satisfy Returns true if any element satisfies the Predicate.

All Satisfy Returns true if all elements satisfy the Predicate.

Presenter
Presentation Notes
anySatisfy() corresponds to a logical “or” allSatisfy() corresponds to a logical “and” Both methods, and detect(), short circuit when possible We’re slowly building up a RichIterable cheat-sheet

KATA EXERCISE 3

69

KA

TA Exercise 3

•Fix Exercise3Test.

•Use the other iteration patterns that take a Predicate.

•Should take about 20 minutes.

70

Presenter
Presentation Notes
No exercises cover immutable data structures because their usage looks so similar to mutable data structures.

KA

TA Solution 3

private static final Predicate<Customer> CUSTOMER_FROM_LONDON =

Predicates.attributeEqual(Customer.TO_CITY, "London"); public void doAnyCustomersLiveInLondon() {

boolean anyCustomersFromLondon = this.company.getCustomers().anySatisfy(CUSTOMER_FROM_LONDON); Assert.assertTrue(anyCustomersFromLondon); }

71

Presenter
Presentation Notes
<solution>

KA

TA Solution 3

public void doAllCustomersLiveInLondon() {

boolean allCustomersFromLondon = this.company.getCustomers().allSatisfy(CUSTOMER_FROM_LONDON); Assert.assertFalse(allCustomersFromLondon); }

72

Presenter
Presentation Notes
<solution>

KA

TA Solution 3

public void howManyCustomersLiveInLondon() {

int numberOfCustomerFromLondon = this.company.getCustomers() .count(CUSTOMER_FROM_LONDON); Assert.assertEquals(2, numberOfCustomerFromLondon); }

73

Presenter
Presentation Notes
<solution>

KA

TA Solution 3

public void getLondonCustomers() {

MutableList<Customer> customersFromLondon = this.company.getCustomers() .select(CUSTOMER_FROM_LONDON); Verify.assertSize(2, customersFromLondon); }

74

Presenter
Presentation Notes
<solution>

KA

TA Solution 3

public void getCustomersWhoDontLiveInLondon() {

MutableList<Customer> customersNotFromLondon = this.company.getCustomers() .reject(CUSTOMER_FROM_LONDON); Verify.assertSize(1, customersNotFromLondon); }

75

Presenter
Presentation Notes
<solution>

KA

TA Solution 3

public class Company { ... public Customer getCustomerNamed(String name) { return this.customers.detect( Predicates.attributeEqual(Customer.TO_NAME, name)); } }

76

Not closure

Presenter
Presentation Notes
<solution>

ADVANCED TESTUTILS

77

AD

VAN

CED TESTU

TILS Verify

Verify includes additional assertions based on iteration patterns.

Code Example

MutableList<Integer> list = FastList.newListWith(1, 2, 0, -1); Verify.assertAllSatisfy(list,

IntegerPredicates.isPositive());

junit.framework.AssertionFailedError: The following items failed to satisfy the condition <[0, -1]>

78

Presenter
Presentation Notes
Type into your IDE Verify.assert and press ctrl+space to have a look at more methods available on Verify. Only a few of them are covered in the Kata.

QU

ESTION

S

79

Presenter
Presentation Notes
<solution>

TARGET COLLECTIONS

80

TA

RGET C

OLLECTIO

NS

Iteration Pattern

• Let's say we have 3 people: mrSmith, mrsSmith, mrJones. • The first two share the same address.

• What will get printed by the following code?

Example Code

MutableSet<Person> people = UnifiedSet.newSetWith(mrSmith, mrsSmith, mrJones); int numAddresses = people.collect(addressFunction).size(); System.out.println(numAddresses);

81

TA

RGET C

OLLECTIO

NS

Covariant return types

• select(), collect(), etc. are defined with covariant return types:

• MutableCollection.collect() returns a MutableCollection

• MutableList.collect() returns a MutableList

• MutableSet.collect() returns a MutableSet

• Alternate forms take target collections.

Example Code

MutableSet<Person> people = UnifiedSet.newSetWith(mrSmith, mrsSmith, mrJones); int numAddresses = people.collect(addressFunction).size(); System.out.println(numAddresses);

82

TA

RGET C

OLLECTIO

NS

Covariant return types

• select(), collect(), etc. are defined with covariant return types:

• MutableCollection.collect() returns a MutableCollection

• MutableList.collect() returns a MutableList

• MutableSet.collect() returns a MutableSet

• Alternate forms take target collections.

Example Code

MutableSet<Person> people = UnifiedSet.newSetWith(mrSmith, mrsSmith, mrJones);

MutableList<Address> targetList = FastList.<Address>newList(); int numAddresses =

people.collect(addressFunction, targetList).size(); System.out.println(numAddresses); 83

FLATCOLLECT PATTERN

84

FLA

TCO

LLECT PA

TTERN Background on collect()

• flatCollect() is a special case of collect().

• With collect(), when the Function returns a collection, the result is a collection of collections.

Code Example

MutableList<Person> people = ...; Function<Person, MutableList<Address>> addressesFunction = new Function<Person, MutableList<Address>>() {

public MutableList<Address> valueOf(Person person) { return person.getAddresses(); } };

MutableList<MutableList<Address>> addresses = people.collect(addressesFunction);

85

Presenter
Presentation Notes
This code example is very similar but now each person can have several addresses. On the Person class, the accessor method is called getAddresses(), and the function returns a list of addresses. Now collect() returns a List of Lists of Addresses.

FLA

TCO

LLECT PA

TTERN flatCollect()

• flatCollect() outputs a single “flattened” collection instead of a collection of collections.

• The signature of flatCollect() is similar to collect(), except that the Function parameter must map to an Iterable type.

flatCollect(Function<? super T, ? extends Iterable<V>> function);

Code Example

MutableList<Person> people = ...; Function<Person, MutableList<Address>> addressFunction = new Function<Person, MutableList<Address>>() {

public MutableList<Address> valueOf(Person person) { return person.getAddresses(); } };

MutableList<Address> addresses = people.flatCollect(addressFunction);

86

FLA

TCO

LLECT PA

TTERN collect()

MutableList<MutableList<Address>> addresses = people.collect(addressFunction);

flatCollect()

MutableList<Address> addresses = people.flatCollect(addressFunction);

87

Presenter
Presentation Notes
Summary: last lines of the previous two slides.

KATA EXERCISE 4

88

KA

TA Exercise 4

• Fix Exercise4Test.

• Should take about 20 minutes.

89

KA

TA Solution 4

public MutableList<Order> getOrders() { return this.customers.flatCollect( new Function<Customer, Iterable<Order>>() { public Iterable<Order> valueOf(Customer customer) { return customer.getOrders(); } }); } // or public MutableList<Order> getOrders() { return this.customers.flatCollect(Customer.TO_ORDERS); }

90

Presenter
Presentation Notes
<solution>

KA

TA Solution 4

MutableSet<String> actualItemNames = this.company.getOrders() .flatCollect(Order.TO_LINE_ITEMS) .collect(LineItem.TO_NAME,

UnifiedSet.<String>newSet());

91

Presenter
Presentation Notes
<solution>

KA

TA Solution 4

public void findCustomerNames() { MutableList<String> names = this.company.getCustomers() .collect(Customer.TO_NAME); MutableList<String> expectedNames = ...; Assert.assertEquals(expectedNames, names); }

92

Presenter
Presentation Notes
<solution>

QU

ESTION

S

93

Presenter
Presentation Notes
<solution>

STATIC UTILITY

94

STA

TIC UTILITY

Iteration Pattern

• Using methods on the interfaces is the preferred, object-oriented approach.

GS Collections Select with Predicates Factory

MutableList<Integer> mutableList = ...; MutableList<Integer> selected = mutableList.select(Predicates.greaterThan(50));

95

STA

TIC UTILITY

Iteration Pattern

• Using methods on the interfaces is the preferred, object-oriented approach.

• But it’s not always feasible.

• Static utility classes like Iterate, ListIterate, etc. provide interoperability with JCF.

GS Collections Select with Predicates Factory

List<Integer> list = ...; MutableList<Integer> selected = ListIterate.select(list, Predicates.greaterThan(50));

96

STA

TIC UTILITY

Iteration Pattern

• Using methods on the interfaces is the preferred, object-oriented approach.

• But it’s not always feasible.

• Static utility classes like Iterate, ListIterate, etc. provide interoperability with JCF.

• Static utility classes like ArrayIterate and StringIterate show that iteration patterns work on other types as well.

GS Collections Select with Predicates Factory

Integer[] array = ...; MutableList<Integer> selected = ArrayIterate.select(array, Predicates.greaterThan(50)); String string = StringIterate.select( "1a2a3", CharPredicate.IS_DIGIT); Assert.assertEquals("123", string);

97

STA

TIC UTILITY

Iteration Pattern

• Static utility for parallel iteration.

• Hides complexity of writing concurrent code.

• Looks like the serial case.

• Notice the lack of locks, threads, pools, executors, etc.

• Order is preserved in the result.

GS Collections Select with Predicates Factory

List<Integer> list = ...; Collection<Integer> selected = ParallelIterate.select(list, Predicates.greaterThan(50));

98

Presenter
Presentation Notes
This presentation covered the GS Collections interfaces first, and static utility later. However the static utility is older. In some places, there still isn’t feature parity. Parallel iteration for example only exists as static utility.

STA

TIC UTILITY

Cheat Sheet

• Iterate (Iterable)

• ListIterate • ArrayListIterate

• MapIterate (Map)

• LazyIterate (Iterable)

• ArrayIterate (T[])

• StringIterate (String)

• ParallelIterate (Iterable)

• ParallelMapIterate (Map)

• ParallelArrayIterate (T[])

99

Presenter
Presentation Notes
There are other similar cheat sheets in the appendix

BENEFITS OF THE OO API

100

BEN

EFITS OF O

O

Static Utility

• Let’s look at the full implementation of Collections.sort() • What’s wrong with this code?

JCF Sort

public static <T> void sort(List<T> list, Comparator<? super T> c) { Object[] array = list.toArray(); Arrays.sort(array, (Comparator) c); ListIterator iterator = list.listIterator(); for (int i = 0; i < array.length; i++) { iterator.next(); iterator.set(array[i]); } }

101

BEN

EFITS OF O

O

Static Utility

• This code is fine for LinkedList. • The code is suboptimal for ArrayList (and FastList).

• Unnecessary array copy.

• Unnecessary iterator created.

• Unnecessary calls to set().

JCF Sort

public static <T> void sort(List<T> list, Comparator<? super T> c) { Object[] array = list.toArray(); Arrays.sort(array, (Comparator) c); ListIterator iterator = list.listIterator(); for (int i = 0; i < array.length; i++) { iterator.next(); iterator.set(array[i]); } }

102

BEN

EFITS OF O

O

Object Oriented

• FastList has a simpler and more optimal implementation.

• Objects group logic with the data it operates on.

• This logic makes sense for an array-backed structure.

FastList Sort

public FastList<T> sortThis(Comparator<? super T> comparator) { Arrays.sort(this.items, 0, this.size, comparator); return this; }

103

KATA EXERCISE 5

104

KA

TA Exercise 5

• Fix the five methods in Exercise5Test. • Solve them using the static utility classes.

• Exercise 5 should take about 25 minutes.

105

KA

TA Solution 5

public void findSupplierNames() {

MutableList<String> supplierNames = ArrayIterate.collect( this.company.getSuppliers(), Supplier.TO_NAME); MutableList<String> expectedSupplierNames = ...; Assert.assertEquals(expectedSupplierNames, supplierNames); }

106

Presenter
Presentation Notes
<solution>

KA

TA Solution 5

public void countSuppliersWithMoreThanTwoItems() {

Predicate<Supplier> moreThanTwoItems = Predicates.attributeGreaterThan( Supplier.TO_NUMBER_OF_ITEMS, 2); int suppliersWithMoreThanTwoItems = ArrayIterate.count( this.company.getSuppliers(), moreThanTwoItems); Assert.assertEquals(5, suppliersWithMoreThanTwoItems); }

107

Presenter
Presentation Notes
<solution>

KA

TA Solution 5

public class Supplier { ...

public static final Function<Supplier, Integer> TO_NUMBER_OF_ITEMS = new Function<Supplier, Integer>() { public Integer valueOf(Supplier supplier) { return supplier.itemNames.length; } }; ... }

108

Presenter
Presentation Notes
<solution>

KA

TA Solution 5

public void whoSuppliesSandwichToaster() {

Predicate<Supplier> suppliesToaster = new Predicate<Supplier>() { public boolean accept(Supplier supplier) { return supplier.supplies("sandwich toaster"); } }; Supplier toasterSupplier = ArrayIterate.detect( this.company.getSuppliers(), suppliesToaster); Assert.assertNotNull("toaster supplier", toasterSupplier); Assert.assertEquals("Doxins", toasterSupplier.getName()); } 109

Presenter
Presentation Notes
You don’t have to define a supplies() method on Supplier, but it’s a nice abstraction. <solution>

KA

TA Solution 5

public class Supplier { ... public boolean supplies(String name) { return ArrayIterate.contains(this.itemNames, name); } ... }

110

Presenter
Presentation Notes
<solution>

KA

TA Solution 5

public void filterOrderValues() {

List<Order> orders = this.company.getMostRecentCustomer().getOrders(); MutableList<Double> orderValues = ListIterate.collect(orders, Order.TO_VALUE); MutableList<Double> filtered = orderValues.select(Predicates.greaterThan(1.5)); Assert.assertEquals( FastList.newListWith(372.5, 1.75), filtered); }

111

Presenter
Presentation Notes
<solution>

KA

TA Solution 5

// Given public static final Function<Order, Double> TO_VALUE =

new Function<Order, Double>() { public Double valueOf(Order order) { return order.getValue(); } };

112

Presenter
Presentation Notes
<solution>

KA

TA Solution 5

// Given public double getValue() { Collection<Double> itemValues = Iterate.collect( this.lineItems, new Function<LineItem, Double>() { public Double valueOf(LineItem lineItem) { return lineItem.getValue(); } }); return CollectionAdapter.adapt(itemValues)

.injectInto(0.0, AddFunction.DOUBLE_TO_DOUBLE); });

113

Presenter
Presentation Notes
<solution>

KA

TA Solution 5

public void filterOrders() {

List<Order> orders = this.company.getMostRecentCustomer().getOrders(); MutableList<Order> filtered = ListIterate.select( orders, Predicates.attributeGreaterThan(Order.TO_VALUE,

2.0)); Assert.assertEquals( FastList.newListWith(Iterate.getFirst(this.company.getMostRecentCustomer().getOrders())),

filtered);

}

114

Presenter
Presentation Notes
<solution>

QU

ESTION

S

115

Presenter
Presentation Notes
<solution>

REFACTORING TO GS COLLECTIONS

116

REFA

CTORIN

G TO GS C

OLLECTIO

NS

Before

List<Integer> integers = new ArrayList<Integer>();

integers.add(1);

integers.add(2);

integers.add(3);

After

List<Integer> integers = new FastList<Integer>();

integers.add(1);

integers.add(2);

integers.add(3);

Why?

• FastList is a drop-in replacement for ArrayList.

• More memory efficient.

• Opens up the refactoring opportunities coming up next.

117

REFA

CTORIN

G TO GS C

OLLECTIO

NS

Before

List<Integer> integers = new FastList<Integer>();

integers.add(1);

integers.add(2);

integers.add(3);

After

List<Integer> integers = FastList.newList();

integers.add(1);

integers.add(2);

integers.add(3);

Why?

• The static factory methods can infer generic types.

118

REFA

CTORIN

G TO GS C

OLLECTIO

NS

Before

List<Integer> integers = FastList.newList();

integers.add(1);

integers.add(2);

integers.add(3);

After

List<Integer> integers =

FastList.newListWith(1, 2, 3);

Why?

• Varargs support; any number of arguments.

• Never mutated; so you could make it unmodifiable:

FastList.newListWith(1, 2, 3).asUnmodifiable();

• There is also a form that takes another iterable:

FastList.newList(list);

119

Presenter
Presentation Notes
There is a static factory method to correspond with each constructor. One form takes an integer to pre-size the backing array.

REFA

CTORIN

G TO GS C

OLLECTIO

NS

Before

List<Integer> integers =

FastList.newListWith(1, 2, 3);

After

MutableList<Integer> integers =

FastList.newListWith(1, 2, 3);

Why?

• MutableList is a drop in replacement for List

•Methods available on interface instead of utility classes.

•Better type information:

• Iterate.select() returns a Collection, but

• MutableList.select() returns a MutableList

120

REFA

CTORIN

G TO GS C

OLLECTIO

NS

Sets and Maps

These refactorings are analogous for UnifiedSet and UnifiedMap:

UnifiedSet<Integer> set =

UnifiedSet.newSetWith(1, 2, 3);

UnifiedMap<Integer, String> map =

UnifiedMap.newWithKeysValues(

1, "1",

2, "2",

3, "3");

121

KATA EXERCISE 6

122

KA

TA Exercise 6

• Fix Exercise6Test. • Two of the ones you just solved.

• This time, don’t use static utility, refactor the domain instead.

• Exercise 6 should take about 10 minutes.

123

KA

TA Solution 6 Quote

“The primary purpose of a compiler is to translate source code into some other form, but in statically typed languages, you can do much more with a compiler. You can take advantage of its type checking and use it to identify changes you need to make. I call this practice leaning on the compiler.”

124

Presenter
Presentation Notes
First change the return type of getOrders(). Next follow the compiler errors until you’re done. The IDE can help you a lot.

QU

ESTION

S

125

Presenter
Presentation Notes
<solution>

MORE ITERATION PATTERNS

126

ITERATIO

N PA

TTERNS

Patterns seen so far

Short-circuit patterns

127

select Returns the elements of a collection that satisfy the Predicate.

reject Returns the elements of a collection that do not satisfy the Predicate.

count Returns the number of elements that satisfy the Predicate.

collect Transforms the elements using a Function.

flatCollect Transforms and flattens the elements using a Function.

detect Finds the first element that satisfies the Predicate.

anySatisfy Returns true if any element satisfies the Predicate.

allSatisfy Returns true if all elements satisfy the Predicate.

ITERATIO

N PA

TTERNS

Additional patterns

128

forEach Executes the Procedure on each element, doesn't return anything.

injectInto Starts with an accumulator and executes a Function2 (a two-argument function) over each element passing the previous accumulated result.

chunk Splits the collection into chunks of the given size.

zip Joins two collections into one collection of Pairs.

makeString Like toString(), with a customizable separator, start, and end string.

toList / toSet Converts the collection to a new copy of the correct type.

toSortedList Returns a new list sorted according to some Comparator.

sortThis Sorts the list in place (mutating method) according to some Comparator.

min / max Returns the min / max element of a collection according to some Comparator.

ITERATIO

N PA

TTERNS

makeString()

• makeString() returns a String representation, similar to toString(). • Three forms:

• makeString(start, separator, end) • makeString(separator) defaults start and end to empty strings

• makeString() defaults the separator to ", " (comma and space)

Code Example

MutableList<Integer> list = FastList.newListWith(1, 2, 3);

assertEquals("[1/2/3]", list.makeString("[", "/", "]")); assertEquals("1/2/3", list.makeString("/")); assertEquals("1, 2, 3", list.makeString()); assertEquals( list.toString(), list.makeString("[", ", ", "]"));

129

Presenter
Presentation Notes
makeString() takes a start and end string and a separator, or you can use one of the overloaded forms that provides defaults for those parameters.

ITERATIO

N PA

TTERNS

appendString()

• appendString() is similar to makeString(), but it appends to an Appendable and is void . • Common Appendables are StringBuilder, PrintStream, BufferedWriter, etc.

• Same three forms, with additional first argument, the Appendable .

Code Example

MutableList<Integer> list = FastList.newListWith(1, 2, 3);

Appendable appendable = new StringBuilder(); list.appendString(appendable, "[", "/", "]"); assertEquals("[1/2/3]", appendable.toString());

130

Presenter
Presentation Notes
appendString is just like makeString() except it has an additional parameter, an Appendable which it writes to, and it doesn't return anything. Some common Appendables included in the JDK are StringBuilder, StringBuffer, PrintStream, and BufferedWriter.

ITERATIO

N PA

TTERNS

chunk()

• chunk() splits a RichIterable into fixed size pieces.

• Final chunk will be smaller if the size doesn't divide evenly.

Code Example

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); // prints [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]

131

ITERATIO

N PA

TTERNS

zip()

• zip() takes a second RichIterable and pairs up all the elements.

• If one of the two RichIterables is longer, its extra elements are ignored.

Code Example

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); // prints [One:Four, Two:Five, Three:Six] 132

ITERATIO

N PA

TTERNS

zipWithIndex()

• A special case is when you want to zip() the elements in a collection with their index positions.

• You could accomplish that with zip() and Interval, or use zipWithIndex() .

Code Example

MutableList<String> list = FastList.newListWith("One", "Two", "Three"); MutableList<Pair<String, Integer>> pairs = list.zipWithIndex(); System.out.println(pairs); // prints [One:0, Two:1, Three:2]

133

ITERATIO

N PA

TTERNS

Iteration Pattern

• min() and max() take a Comparator and return the extreme elements.

• Overloads don’t take a Comparator. • If the elements are not Comparable, you get a ClassCastException.

• What if you don’t want the maximum age, but instead the oldest Person?

Code Example

MutableList<Person> people = ...; Integer maxAge = people.collect(Person.TO_AGE).max();

134

ITERATIO

N PA

TTERNS

Iteration Pattern

• min() and max() take a Comparator and return the extreme elements.

• Overloads don’t take a Comparator. • If the elements are not Comparable, you get a ClassCastException.

• What if you don’t want the maximum age, but instead the oldest Person?

• Use minBy() and maxBy() instead.

Code Example

MutableList<Person> people = ...; Integer maxAge = people.collect(Person.TO_AGE).max(); Person oldestPerson = people.maxBy(Person.TO_AGE);

135

Presenter
Presentation Notes
int maxAge = people.maxBy(Person.TO_AGE).getAge(); This would generate less transient garbage and could return the primitive value.

ITERATIO

N PA

TTERNS

Iteration Pattern

• toSortedList() takes a Comparator and returns a new sorted list.

• Overload doesn’t take a Comparator. • If the elements are not Comparable, you get a ClassCastException.

• What if you don’t want to sort the ages, but instead sort the people by age?

• Use sortThisBy() instead.

Code Example

MutableList<Person> people = ...; MutableList<Integer> sortedAges = people.collect(Person.TO_AGE).toSortedList(); MutableList<Person> peopleSortedByAge = people.toSortedListBy(Person.TO_AGE);

136

KATA EXERCISE 7

137

KA

TA Exercise 7

• Fix Exercise7Test. • Exercises use some of the iteration patterns you have just learned.

• Some use a combination of iteration patterns you have already seen.

• Exercise 7 should take about 20 minutes.

138

KA

TA Solution 7

public void sortedTotalOrderValue() {

MutableList<Double> sortedTotalValues = this.company.getCustomers() .collect(Customer.TO_TOTAL_ORDER_VALUE) .toSortedList(); Assert.assertEquals(Double.valueOf(857.0),

sortedTotalValues.getLast());

Assert.assertEquals(Double.valueOf(71.0), sortedTotalValues.getFirst());

}

139

Presenter
Presentation Notes
<solution>

KA

TA Solution 7

public void maximumTotalOrderValue() {

Double maximumTotalOrderValue = this.company.getCustomers() .collect(Customer.TO_TOTAL_ORDER_VALUE) .max(); Assert.assertEquals(Double.valueOf(857.0), maximumTotalOrderValue); }

140

Presenter
Presentation Notes
<solution>

KA

TA Solution 7

public void customerWithMaxTotalOrderValue() {

Customer customerWithMaxTotalOrderValue = this.company.getCustomers() .maxBy(Customer.TO_TOTAL_ORDER_VALUE); Assert.assertEquals( this.company.getCustomerNamed("Mary"), customerWithMaxTotalOrderValue); }

141

Presenter
Presentation Notes
<solution>

KA

TA Solution 7

public void supplierNamesAsTildeDelimitedString() {

MutableList<String> supplierNames = ArrayIterate.collect(

this.company.getSuppliers(), Supplier.TO_NAME); String tildeSeparatedNames =

supplierNames.makeString("~"); Assert.assertEquals( "Shedtastic~Splendid Crocks~Annoying Pets~Gnomes 'R' Us~Furniture

Hamlet~SFD~Doxins",

tildeSeparatedNames); }

142

Presenter
Presentation Notes
<solution>

KA

TA Solution 7

public void deliverOrdersToLondon() {

this.company.getCustomers() .select(Predicates.attributeEqual( Customer.TO_CITY, "London")) .flatCollect(Customer.TO_ORDERS) .forEach(Order.DELIVER); Verify.assertAllSatisfy( this.company.getCustomerNamed("Fred").getOrders(), Order.IS_DELIVERED); Verify.assertAllSatisfy( this.company.getCustomerNamed("Mary").getOrders(), Predicates.not(Order.IS_DELIVERED)); Verify.assertAllSatisfy( this.company.getCustomerNamed("Bill").getOrders(), Order.IS_DELIVERED); } 143

Presenter
Presentation Notes
I like Order.DELIVER. Similar to Order::deliver when JDK 8 arrives. <solution>

QU

ESTION

S

144

Presenter
Presentation Notes
<solution>

STACK

145

STACK

Stack

• java.util.Stack extends Vector • How does java.util.Stack iterate?

JCF Problems

java.util.Stack stack = new java.util.Stack(); stack.push(1); stack.push(2); stack.push(3); System.out.println(stack); // Prints [1, 2, 3]

146

Presenter
Presentation Notes
Mention that Stack inherits the add and remove methods from Collection

ITERATIO

N PA

TTERNS

Inheritance Hierarchy Stacks

• ArrayStack is not a drop-in replacement for java.util.Stack.

• MutableStack does not extend Collection.

147

Presenter
Presentation Notes
We chose not to extend ArrayList when implementing FastList mainly for efficiency reasons.

STACK

push()

push() adds an item to the top of the MutableStack

MutableStack<Integer> stack = ArrayStack.newStackWith(1, 2, 3); System.out.println(stack); // Prints [3, 2, 1] stack.push(4); System.out.println(stack); // Prints [4, 3, 2, 1]

148

Presenter
Presentation Notes
Java stack returns the item on push

STACK

Code Example

The different ways to create a MutableStack System.out.println(ArrayStack.newStackWith(1, 2, 3)); // Prints [3, 2, 1] System.out.println( ArrayStack.newStackFromTopToBottom(1, 2, 3)); // Prints [1, 2, 3] System.out.println( ArrayStack.newStack(FastList.newListWith(1, 2, 3))); // Prints [3, 2, 1] System.out.println( ArrayStack.newStackFromTopToBottom( FastList.newListWith(1, 2, 3))); // Prints [1, 2, 3]

149

STACK

pop()

Overloaded pop() methods:

pop() pop(int count) pop(int count, R targetCollection)

Code Example

ArrayStack<Integer> stack1 = ArrayStack.newStackWith(1, 2, 3); Assert.assertEquals( FastList.newListWith(3, 2), stack1.pop(2)); ArrayStack<Integer> stack2 = ArrayStack.newStackWith(1, 3, 3); Assert.assertEquals( UnifiedSet.newSetWith(3), stack2.pop(2, UnifiedSet.<Integer>newSet())); ArrayStack<Integer> stack3 = ArrayStack.newStackWith(1, 2, 3); Assert.assertEquals( ArrayStack.newStackWith(3, 2), stack3.pop(2, ArrayStack.<Integer>newStack()));

150

Presenter
Presentation Notes
Explain how it returns a FastList/Listerable

STACK

peek(), peek(int count)

MutableStack has an overloaded peek() method that returns a ListIterable

Code Example

MutableStack<Integer> stack = ArrayStack.newStackWith(1, 2, 3); Assert.assertEquals( Integer.valueOf(3), stack.peek()); Assert.assertEquals( FastList.newListWith(3, 2), stack.peek(2));

151

STACK

MutableStack

MutableStack does not extend java.util.List (or Collection)

JCF Problems

java.util.Stack stack = new java.util.Stack(); stack.push(1); stack.push(2); stack.push(3); Assert.assertEquals(FastList.newListWith(1, 2, 3), stack); stack.add(2, 4); Assert.assertEquals(FastList.newListWith(1, 2, 4, 3), stack); stack.remove(1); Assert.assertEquals(FastList.newListWith(1, 4, 3), stack);

152

Presenter
Presentation Notes
Output: [1, 2, 4, 3] [1, 4, 3]

STACK

Stack API

Code Example

StackIterable<Integer> stack = ArrayStack.newStackFromTopToBottom(1, 2, 3, 4, 5); StackIterable<Integer> evens = stack.select(new Predicate<Integer>() { public boolean accept(Integer integer) { System.out.print(integer + " "); return integer % 2 == 0; } }); // Prints 1 2 3 4 5 Assert.assertEquals(ArrayStack.newStackFromTopToBottom(2, 4), evens);

153

Methods Inherited from

select(), collect(), etc. RichIterable

peek() StackIterable

push(), pop() MutableStack

Presenter
Presentation Notes
There is a conversion method toStack() on ListIterable. MutableBags are regular Collections, so it has methods like add() and remove(). The code example also shows the method addOccurrences() which has the same effect as calling add() several times but is more brief It also shows the method occurrencesOf() which looks up the count from the backing map.

BAG

154

BA

G New Type

• Useful when you would otherwise use Map<K, Integer> • For example, find the number of people who live in each state

Code Example

MutableList<Person> people = ...; MutableList<String> usStates =

people.collect(US_STATE_FUNCTION); MutableMap<String, Integer> stateCounts =

UnifiedMap.newMap(); ... int newYorkers = stateCounts.get("NY");

155

BA

G New Type

• Useful when you would otherwise use Map<K, Integer> • For example, find the number of people who live in each state.

• Lots of boilerplate code to deal with uninitialized counts.

Map Example

MutableMap<String, Integer> stateCounts = UnifiedMap.newMap();

for (String state : usStates) { Integer count = stateCounts.get(state); if (count == null) { count = 0; } stateCounts.put(state, count + 1); } 156

BA

G Before

MutableMap<String, Integer> stateCounts = UnifiedMap.newMap();

for (String state : usStates) { Integer count = stateCounts.get(state); if (count == null) { count = 0; } stateCounts.put(state, count + 1); }

157

BA

G Before

MutableMap<String, Integer> stateCounts = UnifiedMap.newMap();

for (String state : usStates) { Integer count = stateCounts.get(state); if (count == null) { count = 0; } stateCounts.put(state, count + 1); } After

MutableBag<String> stateCounts = HashBag.newBag(); for (String state : usStates) { stateCounts.add(state); } int newYorkers = stateCounts.occurrencesOf("NY");

158

BA

G Before

MutableMap<String, Integer> stateCounts = UnifiedMap.newMap();

for (String state : usStates) { Integer count = stateCounts.get(state); if (count == null) { count = 0; } stateCounts.put(state, count + 1); } After

MutableBag<String> stateCounts = usStates.toBag(); int newYorkers = stateCounts.occurrencesOf("NY");

159

BA

G New Type

• Implemented as a map of key to count.

• Like a List, but unordered.

• Like a Set, but allows duplicates.

Bag Example

MutableBag<String> stateCounts = usStates.toBag(); int newYorkers = stateCounts.occurrencesOf("NY");

160

BA

G Class Diagram

Iterable RichIterable

MutableCollection

MutableList

MutableSet

MutableBag

ImmutableCollection

ImmutableList

ImmutableSet

ImmutableBag

161

BA

G Class Diagram

RichIterable Bag

MutableBag

HashBag

SynchronizedBag

UnmodifiableBag ImmutableBag

162

Presenter
Presentation Notes
Clean split between mutable / immutable There is JDK interoperability in that MutableBag is a MutableCollection, and thus a java.util.Collection However, there is no such thing as java.util.Bag Bags have all the concrete implementations you'd expect, including mutable and immutable implementations, and synchronized and unmodifiable wrappers. equals() and hashCode() in terms of Bag, and the backing map of key to count. Again, mutability doesn't matter so a MutableBag can be equals to an ImmutableBag, but never to any other collection. the equals() method is very useful for assertions since it has a fairly loose contract. For example, if two lists should have the same contents but not necessarily the same order you have two choices. You can sort them and then assert they are equal, or you can convert them both to Bags and assert that the bags are equal. Converting them to bags can be done in linear time.

BA

G Bag API

Code Example

MutableBag<String> bag = HashBag.newBagWith("one", "two", "two", "three", "three", "three");

Assert.assertEquals(3, bag.occurrencesOf("three"));

bag.add("one"); Assert.assertEquals(2, bag.occurrencesOf("one"));

bag.addOccurrences("one", 4); Assert.assertEquals(6, bag.occurrencesOf("one"));

163

Methods Inherited from

select(), collect(), etc. RichIterable

add(), remove(), iterator(), etc. MutableCollection (java.util.Collection)

occurrencesOf(), forEachWithOccurrences(), toMapOfItemToCount()

Bag

addOccurrences(), removeOccurrences() MutableBag

Presenter
Presentation Notes
There is a conversion method toBag() on RichIterables. MutableBags are regular Collections, so it has methods like add() and remove(). The code example also shows the method addOccurrences() which has the same effect as calling add() several times but is more brief It also shows the method occurrencesOf() which looks up the count from the backing map.

MULTIMAP

164

MU

LTIMA

P New Type

• Multimap is similar to Map, but associates a key to multiple values.

• Useful when you would otherwise use Map<K, Collection<V>> • For example, find which people live in each state.

Code Example

MutableList<Person> people = ...; MutableMap<String, MutableList<Person>> statesToPeople = UnifiedMap.newMap(); ... MutableList<Person> newYorkers =

statesToPeople.get("NY"); 165

Presenter
Presentation Notes
Multimaps are implemented by containing a backing Map that maps K to Collections of V.

MU

LTIMA

P New Type

• Multimap is similar to Map, but associates a key to multiple values.

• Useful when you would otherwise use Map<K, Collection<V>> • For example, find which people live in each state.

• Lots of boilerplate code to deal with uninitialized backing collections.

Map Example

MutableMap<String, MutableList<Person>> statesToPeople = UnifiedMap.newMap();

for (Person person : people) { String state = US_STATE_FUNCTION.valueOf(person); MutableList<Person> peopleInState = statesToPeople.get(state); if (peopleInState == null) { peopleInState = FastList.newList(); statesToPeople.put(state, peopleInState); } peopleInState.add(person); } 166

MU

LTIMA

P Before

MutableMap<String, MutableList<Person>> statesToPeople = UnifiedMap.newMap();

for (Person person : people) { String state = US_STATE_FUNCTION.valueOf(person); MutableList<Person> peopleInState = statesToPeople.get(state); if (peopleInState == null) { peopleInState = FastList.newList(); statesToPeople.put(state, peopleInState); } peopleInState.add(person); }

167

MU

LTIMA

P Before

MutableMap<String, MutableList<Person>> statesToPeople = UnifiedMap.newMap();

for (Person person : people) { String state = US_STATE_FUNCTION.valueOf(person); MutableList<Person> peopleInState = statesToPeople.get(state); if (peopleInState == null) { peopleInState = FastList.newList(); statesToPeople.put(state, peopleInState); } peopleInState.add(person); } After

MutableListMultimap<String, Person> statesToPeople = FastListMultimap.newMultimap(); for (Person person : people) { String state = US_STATE_FUNCTION.valueOf(person); statesToPeople.put(state, person); } MutableList<Person> newYorkers =

statesToPeople.get("NY"); 168

MU

LTIMA

P Before

MutableMap<String, MutableList<Person>> statesToPeople = UnifiedMap.newMap();

for (Person person : people) { String state = US_STATE_FUNCTION.valueOf(person); MutableList<Person> peopleInState = statesToPeople.get(state); if (peopleInState == null) { peopleInState = FastList.newList(); statesToPeople.put(state, peopleInState); } peopleInState.add(person); } After

MutableListMultimap<String, Person> statesToPeople = people.groupBy(US_STATE_FUNCTION); MutableList<Person> newYorkers =

statesToPeople.get("NY");

169

Presenter
Presentation Notes
The argument passed to groupBy is a Function, just like collect(). Our function here is US_STATE_FUNCTION. Note that the types on the Function are reversed from the types on the Multimap. Multimap<String, Person> - A Multimap of States to People Function<Person, String> - A Function that takes a Person and returns their State

MU

LTIMA

P Multimap

• What happens if you add the same key and value twice?

Code Example

MutableMultimap<String, Person> multimap = ...; multimap.put("NY", person); multimap.put("NY", person); RichIterable<Person> ny = multimap.get("NY");

Verify.assertIterableSize(?, ny);

170

Presenter
Presentation Notes
We know that a multimap can have multiple values at one key. But what happens if we add the same exact value twice at the same key? Take a guess, what is the size of the collection on the last line?

MU

LTIMA

P Multimap

• What happens if you add the same key and value twice?

• Depends on the type of the backing collection.

Code Example

MutableListMultimap<String, Person> multimap = FastListMultimap.newMultimap(); multimap.put("NY", person); multimap.put("NY", person); MutableList<Person> ny = multimap.get("NY");

Verify.assertIterableSize(2, ny);

171

Presenter
Presentation Notes
The answer depends on the type of the collections held by the backing map. If you're using a MutableListMultimap, then the backing collections are Lists, which allow duplicates. So the result of the call to get() on the last line will be a MutableList of size 2.

MU

LTIMA

P Multimap

• What happens if you add the same key and value twice?

• Depends on the type of the backing collection.

Code Example

MutableSetMultimap<String, Person> multimap = UnifiedSetMultimap.newMultimap(); multimap.put("NY", person); multimap.put("NY", person); MutableSet<Person> ny = multimap.get("NY");

Verify.assertIterableSize(1, ny);

172

Presenter
Presentation Notes
If you're using a MutableSetMultimap, then the backing collections are Sets, which do not allow duplicates. So the result of the call to get() on the last line will be a MutableSet of size 1. When you add an element to a set twice, nothing happens the second time. Similarly nothing happens to this multimap the second time we call put(). The backing collections can be Lists, Sets, or Bags. In theory, we can make Multimaps backed by any RichIterable. You cannot have a Multimap of Maps or a Multimap of Multimaps because they aren’t RichIterable.

MU

LTIMA

P Class Diagram

Multimap

MutableMultimap

MutableListMultimap

MutableSetMultimap

MutableBagMultimap

ImmutableMultimap

ImmutableListMultimap

ImmutableSetMultimap

ImmutableBagMultimap

173

Presenter
Presentation Notes
Multimap does not extend RichIterable or anything else (at least for now). There's a clean split between the mutable and immutable sides. equals() and hashCode() are implemented in terms of the backing collections. Mutability doesn't matter. So a MutableListMultimap can be equal to an ImmutableListMultimap. But neither one can ever be equal to a BagMultimap.

CO

LLECTION

S HEIRA

RCHY

Collection Types

• List

• Set

• Map

• Stack

• Bag

• Multimap Mutability

• Mutable

• Immutable

Decorators

• Synchronized

• Unmodifiable

174

Presenter
Presentation Notes
There are several orthogonal concepts in the collection hierarchy, and nearly every combination exists now. For example: UnmodifiableBag, ImmutableMultimap.

KATA EXERCISE 8

175

KA

TA Exercise 8

• Fix Exercise8Test. • Refactor the repetition at TODO 8 in CompanyDomainForKata without

breaking anything.

• Exercise 8 should take about 30 minutes.

176

KA

TA Solution 8

public void customersByCity() { MutableListMultimap<String, Customer> multimap = this.company.getCustomers().groupBy(Customer.TO_CITY);

... }

177

Presenter
Presentation Notes
<solution>

KA

TA Solution 8

public void mapOfItemsToSuppliers() { final MutableMultimap<String, Supplier> itemsToSuppliers = FastListMultimap.newMultimap(); ArrayIterate.forEach( this.company.getSuppliers(), new Procedure<Supplier>() { public void value(final Supplier supplier) { ArrayIterate.forEach( supplier.getItemNames(), new Procedure<String>() { public void value(String itemName) { itemsToSuppliers.put(itemName, supplier); } }); } }); Verify.assertIterableSize(2, itemsToSuppliers.get("sofa")); } 178

Presenter
Presentation Notes
<solution>

KA

TA Solution 8

public class Order { private final MutableBag<LineItem> lineItems = HashBag.newBag(); ... public void addLineItems(LineItem aLineItem, int

occurrences) { this.lineItems.addOccurrences(aLineItem, occurrences); } ... }

179

Presenter
Presentation Notes
<solution>

KA

TA Solution 8

private void setUpCustomersAndOrders() { ... order.addLineItems(new LineItem("cup", 1.5), 3); ... }

180

Presenter
Presentation Notes
<solution>

MU

LTIMA

P groupByEach()

• groupByEach() is a special case of groupBy().

• Analogous to the difference between collect() and flatCollect().

• Appropriate when the Function returns a collection.

• The return type is the same as groupBy().

Refactor Exercise8Test.mapOfItemsToSuppliers() to use groupByEach().

Code Example

MutableListMultimap<String, Person> statesToPeople = people.groupBy(US_STATE_FUNCTION); MutableListMultimap<String, Person> statesToPeople = people.groupByEach(US_STATES_FUNCTION);

181

Presenter
Presentation Notes
Now each person can have several addresses. The code for US_STATES_FUNCTION is not shown, but the generics are different. It’s a Function<Person, Iterable<String>> It would work if Iterable were replaced with any other type of Iterable (any subclass).

MU

LTIMA

P Kata

Refactor Exercise8Test.mapOfItemsToSuppliers() to use groupByEach().

Use an ArrayAdapter.

public void mapOfItemsToSuppliers_refactored() { MutableList<Supplier> suppliersList = ArrayAdapter.adapt(this.company.getSuppliers()); ... }

182

Presenter
Presentation Notes
Now each person can have several addresses. The code for US_STATES_FUNCTION is not shown, but the generics are different. It’s a Function<Person, Iterable<String>> It would work if Iterable were replaced with any other type of Iterable (any subclass).

KA

TA Solution 8

public void mapOfItemsToSuppliers_refactored() { MutableList<Supplier> suppliersList = ArrayAdapter.adapt(this.company.getSuppliers()); MutableListMultimap<String, Supplier> itemsToSuppliers = suppliersList.groupByEach(Supplier.TO_ITEM_NAMES); Verify.assertIterableSize(2, itemsToSuppliers.get("sofa")); }

183

Presenter
Presentation Notes
<solution>

QU

ESTION

S

184

Presenter
Presentation Notes
<solution>

LAZY EVALUATION

185

LAZY E

VALU

ATIO

N Eager Evaluation

• This example uses eager evaluation.

• When do the calls to valueOf() and accept() take place?

• We can create our own Function and Predicate to answer the question.

Code Example

Person person1 = new Person(address1); Person person2 = new Person(address2); Person person3 = new Person(address3);

MutableList<Person> people = FastList.newListWith(person1, person2, person3); MutableList<Address> addresses = people.collect(addressFunction); Assert.assertTrue(addresses.anySatisfy(Predicates.equal(address2)));

186

LAZY E

VALU

ATIO

N Eager Evaluation

• Function from Person to Address. • Maintains internal mutable state.

• Not functional style.

• Not thread-safe.

Code Example

public class AddressFunction implements Function<Person, Address> { private int counter = 1; public Address valueOf(Person person) { System.out.println("Function: " + this.counter); this.counter++; return person.getAddress(); } }

187

LAZY E

VALU

ATIO

N Eager Evaluation

• Predicate returns true when address is the same reference as this.address

• Maintains internal mutable state.

• Not functional style.

• Not thread-safe.

Code Example

public class EqualsAddressPredicate implements Predicate<Address> { private final Address address; private int counter = 1; private EqualsAddressPredicate(Address address) { this.address = address; }

public boolean accept(Address address) { System.out.println("Predicate: " + this.counter); this.counter++; return address == this.address; } }

188

LAZY E

VALU

ATIO

N Eager Evaluation

• When do the calls to valueOf() and accept() take place?

Code Example

MutableList<Address> addresses = people.collect(new AddressFunction()); addresses.anySatisfy( new EqualsAddressPredicate(address2));

189

LAZY E

VALU

ATIO

N Eager Evaluation

• When do the calls to valueOf() and accept() take place?

Code Example

MutableList<Address> addresses = people.collect(new AddressFunction()); // Function: 1 // Function: 2 // Function: 3

addresses.anySatisfy( new EqualsAddressPredicate(address2)); //Predicate: 1 //Predicate: 2 190

LAZY E

VALU

ATIO

N Definition

• According to Wikipedia, lazy evaluation is “the technique of delaying a computation until its value is actually required.”

• When do the calls to valueOf() and accept() take place?

Code Example

LazyIterable<Person> peopleLazy = people.asLazy(); LazyIterable<Address> addressesLazy = peopleLazy.collect(new AddressFunction()); addressesLazy.anySatisfy( new EqualsAddressPredicate(address2));

191

LAZY E

VALU

ATIO

N Definition

• According to Wikipedia, lazy evaluation is “the technique of delaying a computation until its value is actually required.”

• When do the calls to valueOf() and accept() take place?

Code Example

LazyIterable<Person> peopleLazy = people.asLazy(); LazyIterable<Address> addressesLazy = peopleLazy.collect(new AddressFunction()); addressesLazy.anySatisfy( new EqualsAddressPredicate(address2)); // Function: 1 // Predicate: 1 // Function: 2 // Predicate: 2

192

Presenter
Presentation Notes
New interface LazyIterable Mostly a marker communicating lazy evaluation asLazy() returns the collection wrapped in a LazyIterable adapter

LAZY E

VALU

ATIO

N Eager Evaluation

MutableList<Address> addresses = people.collect(new AddressFunction()); // Function: 1 // Function: 2 // Function: 3 addresses.anySatisfy(new EqualsAddressPredicate(address2)); //Predicate: 1 //Predicate: 2

Lazy Evaluation

Why would we prefer lazy evaluation? LazyIterable<Person> peopleLazy = people.asLazy(); LazyIterable<Address> addressesLazy = peopleLazy.collect(new AddressFunction()); addressesLazy.anySatisfy(new EqualsAddressPredicate(address2)); // Function: 1 // Predicate: 1 // Function: 2 // Predicate: 2 193

Presenter
Presentation Notes
Chained calls to select, collect, reject, etc. create new collections But calls to anySatisfy, allSatisfy, detect, etc. usually only look at part of the collection Eager evaluation can cause unnecessary computation Not necessary to apply the address function to person3 because anySatisfy short circuits

LAZY E

VALU

ATIO

N Definition

• According to Wikipedia, lazy evaluation is “the technique of delaying a computation until its value is actually required.”

• Benefits include:

• Performance increases due to avoiding unnecessary calculations.

• Avoiding error conditions in the evaluation of compound expressions.

• The ability to construct potentially infinite data structures.

194

Presenter
Presentation Notes
The most important benefit is that it performance increases due to avoiding unnecessary calculations. This obviously speeds up execution time. It also avoids unnecessary memory allocation, and it lowers the maximum amount of memory being used at every point in time.

LAZY E

VALU

ATIO

N Avoid Error Conditions

• Test passes.

• No NullPointerException.

Code Example

MutableList<Person> people =

FastList.newListWith(person1, person2, null); LazyIterable<Person> peopleLazy = people.asLazy(); LazyIterable<Address> addressesLazy =

peopleLazy.collect(new AddressFunction()); Assert.assertTrue(addressesLazy.anySatisfy( new EqualsAddressPredicate(address2)));

195

LAZY E

VALU

ATIO

N Class Diagram

Iterable RichIterable

MutableCollection

MutableList

MutableSet

MutableBag

LazyIterable

ImmutableCollection

ImmutableList

ImmutableSet

ImmutableBag

196

Presenter
Presentation Notes
A zoomed out view showing more of the hierarchy. RichIterable and LazyIterable are readable interfaces (meaning they have no mutating methods, but do have mutable subclasses).

LAZY E

VALU

ATIO

N Lazy Evaluation

• LazyIterate provides the utility methods for lazy evaluation.

Code Example

MutableList<Person> people =

FastList.newListWith(person1, person2, null);

LazyIterable<Address> addresses =

LazyIterate.collect(people, addressFunction); Assert.assertTrue( addresses.anySatisfy(Predicates.equal(address2)));

197

Presenter
Presentation Notes
This code example is the same except that if the list of people were not a MutableList, you could still pass it into the utility method LazyIterate.collect().

UNMODIFIABLE AND SYNCHRONIZED WRAPPERS

198

WRA

PPERS Unmodifiable Wrapper

• asUnmodifiable() returns a wrapper which throws on mutating methods.

Test Code

Verify.assertThrows(

UnsupportedOperationException.class,

new Runnable() {

public void run() {

richIterable.asUnmodifiable().add(0);

}

});

199

Presenter
Presentation Notes
asUnmodifiable() returns a wrapper which throws on mutating methods The code example shows how calling add() will throw an UnsupportedOperationException. Often you should prefer ImmutableCollections instead, but there are different time/memory tradeoffs. However, Unmodifiable wrappers are useful in order to share a view on some other object's internal state. You can query an unmodifiable collection to see if it contains some object two times and get different answers each time because the delegate collection is being modified by someone else. Yet you're still protected from external modification. An immutable collection obviously cannot change over time.

WRA

PPERS Java Collections Framework

Collection<Integer> synch =

Collections.synchronizedCollection(collection);

synchronized (synch) {

for (Integer integer : synch) {

System.out.println(integer);

}

}

GS Collections

MutableCollection<Integer> synch =

collection.asSynchronized();

synch.forEach(new Procedure<Integer>() {

public void value(Integer integer) {

System.out.println(integer);

}

});

200

Presenter
Presentation Notes
JDK vs GS Collections. The forEach loop in Java 5 is syntactic sugar. It compiles to bytecode that does use an iterator so it needs to be externally synchronized. If you use the GS Collections forEach method, the locking is completely encapsulated. However, MutableCollections have an iterator() method which is equally unsafe. We considered making it throw an UnsupportedOperationException but we thought that would be too frustrating.

MORE BENEFITS OF THE OO API

201

BEN

EFITS OF O

O

JCF For-Each

• Assume that synchronizedList is shared by several threads.

• What’s wrong with this code?

Code Example

List<Integer> synchronizedList = Collections.synchronizedList(list); printAll(synchronizedList); <T> void printAll(List<T> list) { for (T element : list) { System.out.println(element); } } 202

BEN

EFITS OF O

O

JCF For-Each

• For-Each loop syntax gets compiled to bytecode that uses an iterator.

• This code produces identical bytecode.

Iterator<T> iterator = list.iterator(); while (iterator.hasNext()) { T element = iterator.next(); System.out.println(element); }

Code Example

List<Integer> synchronizedList = Collections.synchronizedList(list); printAll(synchronizedList); <T> void printAll(List<T> list) { for (T element : list) { System.out.println(element); } } 203

BEN

EFITS OF O

O

JCF For-Each

• iterator() is the one method that is not synchronized

• From the JavaDoc of Collections.synchronizedList():

• It is imperative that the user manually synchronize on the returned list when iterating over it:

List list = Collections.synchronizedList(new ArrayList());

... synchronized (list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); } } Failure to follow this advice may result in non-deterministic behavior.

204

BEN

EFITS OF O

O

JCF For-Each

• Using MutableList does not help.

• It is not possible to use Iterator in a thread-safe way.

• How can we fix this code?

Code Example

MutableList<Integer> synchronizedList = list.asSynchronized(); this.printAll(synchronizedList); <T> void printAll(List<T> list) { for (T element : list) { System.out.println(element); } } 205

BEN

EFITS OF O

O

JCF For-Each

• We could put a synchronized block inside the printAll() method.

• Very strange, since the list might not be synchronized.

• We would have to do this in every method that takes a collection.

Code Example

<T> void printAll(List<T> list) { synchronized (list) { for (T element : list) { System.out.println(element); } } }

206

BEN

EFITS OF O

O

Object Oriented

• The forEach() method is the safe way.

• The forEach() method is the object-oriented way.

• Why does this work?

Code Example

<T> void printAll(MutableList<T> list) { list.forEach(new Procedure<T>() { public void value(T element) { System.out.println(element); } }); }

207

BEN

EFITS OF O

O

Object Oriented

• SynchronizedMutableList holds the lock for the duration of the iteration.

• This is the compelling reason to use the forEach() method despite the verbosity.

Code Example

public void forEach(Procedure<? super E> block) { synchronized (this.lock) { this.collection.forEach(block); } }

208

BEN

EFITS OF O

O

Object Oriented

• The code does the correct thing for a: • FastList

• FastList in a SynchronizedMutableList

• FastList in a SynchronizedMutableList in a ListAdapter in a …

• Even if FastList.forEach() is implemented by using an Iterator.

Code Example

<T> void printAll(MutableList<T> list) { list.forEach(new Procedure<T>() { public void value(T element) { System.out.println(element); } }); }

209

TH

READ-SA

FE CO

LLECTION

S Thread-safe Collections

• MultiReaderFastList and MultiReaderUnifiedSet completely encapsulate synchronization.

• iterator() and listIterator() throw UnsupportedOperationException.

• withReadLockAndDelegate() and withWriteLockAndDelegate() allow complete access to the backing collection in a synchronized context.

Code Example

MultiReaderFastList<String> list = MultiReaderFastList.newListWith("1", "2", "3"); list.withWriteLockAndDelegate( new Procedure<MutableList<String>>() { public void value(MutableList<String> backingList) { Iterator<String> iterator = backingList.iterator(); iterator.next(); iterator.remove(); }}); Assert.assertEquals(FastList.newListWith("2", "3"), list);

Presenter
Presentation Notes
From the Javadoc… MultiReadFastList provides a thread-safe wrapper around a FastList, using a ReentrantReadWriteLock. In order to provide true thread-safety, MultiReaderFastList does not implement iterator(), listIterator(), listIterator(int), or get(int), as all of these methods require an external lock to be taken to provide thread-safe iteration. All of these methods are available however, if you use the withReadLockAndDelegate() or withWriteLockAndDelegate() methods. Both of these methods take a parameter of type Procedure , and a wrapped version of the underlying FastList is returned. This wrapper guarantees that no external pointer can ever reference the underlying FastList outside of a locked procedure. In the case of the read lock method, an Unmodifiable version of the collection is offered, which will throw UnsupportedOperationExceptions on any write methods like add or remove.

KATA EXERCISE 9

211

KA

TA Exercise 9

• Fix Exercise9Test. • The final set of exercises is the most difficult and is optional.

212

KA

TA Solution 9

public void whoOrderedSaucers() {

MutableList<Customer> customersWithSaucers = this.company.getCustomers().select( Predicates.attributeAnySatisfy( Customer.TO_ORDERS, Predicates.attributeAnySatisfy( Order.TO_LINE_ITEMS, Predicates.attributeEqual(LineItem.TO_NAME,

"saucer"))));

Verify.assertSize(2, customersWithSaucers); }

213

Presenter
Presentation Notes
<solution>

KA

TA Solution 9

public void mostExpensiveItem() { MutableListMultimap<Double, Customer> multimap = this.company.getCustomers().groupBy( new Function<Customer, Double>() { public Double valueOf(Customer customer) { return customer.getOrders() .asLazy() .flatCollect(Order.TO_LINE_ITEMS) .collect(LineItem.TO_VALUE) .max(); } }); }

214

Presenter
Presentation Notes
<solution>

KA

TA Solution 9

public void mostExpensiveItem() { MutableListMultimap<Double, Customer> multimap = this.company.getCustomers().groupBy( new Function<Customer, Double>() { public Double valueOf(Customer customer) { LazyIterable<LineItem> allOrderedItems = customer.getOrders().asLazy().flatCollect( new Function<Order, Bag<LineItem>>() { public Bag<LineItem> valueOf(Order order) { return order.getLineItems(); } }); LazyIterable<Double> prices = allOrderedItems.collect( new Function<LineItem, Double>() { public Double valueOf(LineItem item) { return item.getValue(); } }); return prices.max(); } }); }

215

Presenter
Presentation Notes
Very memory inefficient. Creates two Function blocks per customer. <solution>

QU

ESTION

S

216

Presenter
Presentation Notes
<solution>

APPENDIX

217

ANONYMOUS INNER CLASS

218

AN

ON

YMO

US IN

NER C

LASS

Definition

• An inner class with no name.

• Looks like a normal constructor call, but it works on abstract types (including interfaces).

• Has a body afterwards which makes the type concrete or overrides method definitions.

• Has a random-looking class name after compilation.

• OuterClass$1 for the first anonymous inner class in OuterClass.

Code Example

Comparator<Person> comparator = new Comparator<Person>() { public int compare(Person o1, Person o2) { return o1.getLastName().compareTo(o2.getLastName()); } }; System.out.println(comparator.getClass());

219

CLOSURE

220

CLO

SURE

Closure Definition

Wikipedia definition:

“[A] closure is a first-class function with free variables that are bound in the lexical environment.

“Such a function is said to be ‘closed over’ its free variables.

“A closure is defined within the scope of its free variables, and the extent of those variables is at least as long as the lifetime of the closure itself.”

• Java does not have closures.

• Java 8 will have lambdas.

221

CLO

SURE

Closure Definition

Java does not have closures.

In the code example, the Predicate is a class with a String field.

It is not the same copy as the method parameter.

Code Example

public Customer getCustomerNamed(String name) { Predicate<Customer> customerNamed = Predicates.attributeEqual(Customer.TO_NAME, name); return this.customers.detect(customerNamed); }

222

CLO

SURE

Closure Definition

Java does not have closures.

In the code example, the Predicate is a class with a String field.

It is not the same copy as the method parameter.

• Changing this copy of name has no effect on the result.

• Maybe obvious because of Java’s rules for parameter passing.

Code Example

public Customer getCustomerNamed(String name) { Predicate<Customer> customerNamed = Predicates.attributeEqual(Customer.TO_NAME, name); name = name + "!"; return this.customers.detect(customerNamed); }

223

CLO

SURE

Closure Definition

Java does not have closures.

In the code example, the Predicate is a class with a String field.

It is not the same copy as the method parameter.

• If you use an anonymous inner class to implement the Predicate, you have to make name final in order to satisfy the compiler.

Code Example

public Customer getCustomerNamed(final String name) { Predicate<Customer> attributeEqual = new Predicate<Customer>() { public boolean accept(Customer customer) { return customer.getName().equals(name); } }; return this.customers.detect(attributeEqual); } 224

CLO

SURE

Closure Definition

Java does not have closures.

In the code example, the Predicate is a class with a String field.

It is not the same copy as the method parameter.

• If you use an anonymous inner class to implement the Predicate, you have to make name final in order to satisfy the compiler.

• Refactor the anonymous inner class to a named inner class and you can see why.

Code Example

private static final class CustomerNamed implements Predicate<Customer> {

private final String name; private CustomerNamed(String name) { this.name = name; } public boolean accept(Customer customer) { return customer.getName().equals(this.name); } } 225

BLOCKS

226

BLO

CKS UML

227

BLO

CKS Function

Function transforms one type (T) to another (V):

public interface Function<T, V> extends Serializable { V valueOf(T object); }

Used in: • collect

• flatCollect • groupBy • minBy • maxBy • toSortedListBy • sortThisBy • toMap

228

BLO

CKS Predicate

Predicate takes an object of some type (T) and returns a boolean:

public interface Predicate<T> extends Serializable { boolean accept(final T each); }

Used in: • select • reject • detect • count • anySatisfy • allSatisfy

229

BLO

CKS Predicate

Procedure takes an object of some type (T) and doesn’t return anything:

public interface Procedure<T> extends Serializable { void value(final T each); }

Used in: • forEach

230

RICHITERABLE

231

RICHITERA

BLE Cheat Sheet

232

collect Transforms elements using a Function into a new collection.

flatCollect Transforms and flattens the elements using a Function.

groupBy Gets a key for each element using a Function and puts the key and element into a Multimap.

RICHITERA

BLE Cheat Sheet

233

sortThisBy Gets some attribute from each element using a Function and sorts the list by the natural order of that attribute.

toSortedListBy Gets some attribute from each element using a Function and returns a new list sorted by the natural order of that attribute.

minBy Gets some attribute from each element and returns the element whose attribute is minimal.

maxBy Gets some attribute from each element and returns the element whose attribute is maximal.

toMap Gets a key and value for each element using two Functions and returns a new map containing all the key/value pairs.

RICHITERA

BLE Cheat Sheet

234

select Returns the elements of a collection that satisfy some condition (Predicate).

reject Returns the elements of a collection that do not satisfy the Predicate.

detect Finds the first element that satisfies the Predicate.

count Returns the number of elements that satisfy the Predicate.

anySatisfy Returns true if any element satisfies the Predicate.

allSatisfy Returns true if all elements satisfy the Predicate.

forEach Executes the Procedure on each element, doesn't return anything.

RICHITERA

BLE Cheat Sheet

235

min Returns the minimum element using either the natural order or a Comparator.

max Returns the maximum element using either the natural order or a Comparator.

toSortedList Returns a new list, sorted using either the natural order or a Comparator.

makeString Converts the collection to a string using optional start, end, and separator strings.

appendString Converts the collection to a string and appends it to an Appendable.

zip Takes a second RichIterable and pairs up all the elements. If one of the two RichIterables is longer than the other, its remaining elements are ignored.

zipWithIndex Zips the collection with the Integer indexes 0 to n-1.

chunk Splits a collection into fixed size chunks. The final chunk will be smaller if the collection doesn't divide evenly.

RICHITERA

BLE Inheritance Hierarchy

236

OPTIMIZATION

237

OPTIM

IZATIO

N collectWith(), selectWith(), and rejectWith()

• collectWith(), selectWith(), and rejectWith() are alternate forms of collect(), select(), and reject().

• Original forms all take a single parameter, a code block which takes a single parameter.

• What if we want to find groups of people at different ages?

Code Example

MutableList<Person> voters = people.select( new Predicate<Person>() { public boolean accept(Person eachPerson) { return eachPerson.getAge() > 18; } });

238

OPTIM

IZATIO

N collectWith(), selectWith(), and rejectWith()

• collectWith(), selectWith(), and rejectWith() are alternate forms of collect(), select(), and reject().

• …with() forms take two parameters:

• a code block which takes two parameters,

• an object that gets passed as the second argument to the code block.

• Store the two-argument block in a constant to avoid object creation.

Code Example

Predicate2<Person, Integer> age = new Predicate2<Person, Integer>() { public boolean accept(Person eachPerson, Integer age) { return eachPerson.getAge() > age; } }; MutableList<Person> drivers = people.selectWith(age, 17); MutableList<Person> voters = people.selectWith(age, 18); MutableList<Person> drinkers = people.selectWith(age, 21); MutableList<Person> sunsetRobotSquad = people.selectWith(age, 160);

239

OPTIM

IZATIO

N

“We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil”

– Donald Knuth

240