http://www.higherorderlogic.com/refactoring-to-functional.zip
Refactoring to
functional
Steve Freeman @sf105
Julian Kelsey @scrawlings, Andy Parker @aparker42
Requires access to a laptop with Java 1.6+ and a refactoring IDE
Today
- What? Why?
- Quick tour of Guava
- Practice on some exercises
- Discuss/Questions
- Try out a larger problem
- Wrap up
Functional programming?
- Stateless
- Immutable
val a = doubled(b) val doubledCounts = eachDoubled(counts)
First class functions
- Unit of behaviour
- Higher-order programming
val plusOne = lambda x: x + 1
val incremented = applied(count, plusOne)
def applied(value, oneArgFunction):
return oneArgFunction(value)
Lots of collections
- Filters, mapping, etc.
- Return a copy
- Might be lazy
val backwards = reversed(forwards) val incremented = map(counts, plusOne) val shouty = map(inputStream, inUpperCase)
incremented = [x + 1 for x in counts]
Collection manipulation
- Convert a collection to a different shape
- concat(), reduce(), split(), index()
- Some can't be lazy
val plusThenMinus = concat( filter(values, isPositive), filter(values, isNegative)) val total = reduce(values, 0, add) val idToAccount = uniqueIndex(accounts, account => account.id)
Why functional?
- Separation of concerns
- Higher-level coding
- Stateless is safer
val allPostiveRecordsAreValid = all(filter(records, isPositive), isValid)
records select (r => r.value > 0)
all (r => r.isValid)
all([r.isValid for r in records
if r.value > 0])
What will be different?
- Lots of “noise” underneath to make the magic happen
- Name results rather than actions
- Radically small components
daily = values.getConvertedToDaily() daily = values asDailyResults
def sum(values):
return reduce(values, 0, adder)
In the real world
- Flush out mutability
- Takes time to learn to see
- Learn a proper functional language
- OO outside and functional inside
In the real world (Java)
- Guava changes the game
- – or other tools that manipulate bytecode
- Excessive amounts of boiler-plate and “<>”
- – lots of helper methods
- – compact code formatting
- Sometimes Java just isn't Haskell
- – watch out for lazy functions that aren't
- Jam tomorrow (Java 8)
Quick intro to Guava
- Google collections library
- Iterator-based
- Lazy (kinda)
Function<I,O>
- Convert from one thing to another
Function<Integer, String> asString = new Function<Integer, String>() { public String apply(Integer input) { return String.valueOf(input); } }; assertEquals("123", asString.apply(123));
Predicate<T>
- Check a condition on a value
Predicate<String> isBlank = new Predicate<String>() { public boolean apply(String input) { return input.matches("\\s*"); } }; assertFalse(isBlank.apply("Some Input")); assertTrue(isBlank.apply(" "));
transform()
- Equivalent of map() in other systems
Iterable<O> transform(Iterable<I>, Function<I, O>)
Iterable<Integer> numbers = asList(1, 2, 3); Iterable<String> strings = Iterables.transform(numbers, asString); assertThat(strings, contains("1", "2", "3"));
filter()
- Selects items from an Iterable
Iterable<T> filter(Iterable<T>, Predicate<T>)
List<Integer> strings = asList("a", " ", "c", " "); Iterable<String> blanks = Iterables.filter(strings, isBlank); assertThat(blanks, contains(" ", " "));
Boolean queries
- Whether items match a predicate
boolean all(Iterable<T>, Predicate<T>)
boolean any(Iterable<T>, Predicate<T>)
assertTrue( Iterables.all(asList(" ", " "), isBlank)); assertFalse(all(asList("s", " "), isBlank)); assertTrue( Iterables.any(asList("a", " "), isBlank)); assertFalse(any(asList("a", "b"), isBlank));
reduce()
- Accumulate a result across a collection
- We've provided one in
RtfIterables(not in Guava)
R reduce(Iterable<I>, R, Function<I, R>)
assertThat(
reduce(asList(1, 2, 3), 0, addition),
equalTo(6));
assertThat(
reduce(asList(1, 2, 3), 10, subtraction),
equalTo(4));









