Transcript
Page 1: Lambdas: Myths and Mistakes

Lambdas:Myths andMistakesby Richard Warburton

Page 2: Lambdas: Myths and Mistakes

Learning FP is so much more than justknowing what map/fold/filter/etc. do. It's

more like getting good at Portal :)

@copumpkin

Page 3: Lambdas: Myths and Mistakes

Who am I?Currently work at jClarity

Focus on performance diagnostics and

static analysis

Adopt a JSR (Date and Time + Lambdas)

Writing a book for O'Reilly Media on

Lambda Expressions in Java 8.

Page 4: Lambdas: Myths and Mistakes

Talk StructureBackground and Motivation

Introduction to Lambda Expressions

Beyond the Myths

Functional Thinking

Page 5: Lambdas: Myths and Mistakes

Backgroundand Motvation

Page 6: Lambdas: Myths and Mistakes

Lambda Expressions arecoming in Java 8!

Page 7: Lambdas: Myths and Mistakes

Lots of discussion/debate

Page 8: Lambdas: Myths and Mistakes

How can we help?Adopt-a-JSR

Page 9: Lambdas: Myths and Mistakes

Adopt-a-JSR?Community driven standards feedback

Hackdays

Serve on Expert Groups

Initiated by Martijn Verburg

Page 10: Lambdas: Myths and Mistakes

Some discussionunimportant

Concrete Examples focus discussion

Page 11: Lambdas: Myths and Mistakes

Introductionto Lambda

Expressions

Page 12: Lambdas: Myths and Mistakes

Overview of LambdasGoal: Better Libraries

Example: Data Parallelism

Approach: Allow Code as Data

Page 13: Lambdas: Myths and Mistakes

Action Listenerbutton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { System.out.println("button clicked"); }});

Page 14: Lambdas: Myths and Mistakes

Code as Databutton.addActionListener( ?);

Page 15: Lambdas: Myths and Mistakes

Need a parameterbutton.addActionListener(event

);

Page 16: Lambdas: Myths and Mistakes

Lambda Examplebutton.addActionListener(event -> System.out.println("button clicked"));

Page 17: Lambdas: Myths and Mistakes

No parametersRunnable helloWorld = () -> System.out.println("Hello World");

Page 18: Lambdas: Myths and Mistakes

Variable CaptureString name = getUserName();button.addActionListener(event -> System.out.println("hi " + name));

Page 19: Lambdas: Myths and Mistakes

Functional InterfacesEverything in Java has a type

Problem: Need types to represent

Functions

Solution: Use interfaces

Page 20: Lambdas: Myths and Mistakes

Functional Interfacespublic interface ActionListener extends EventListener { public void actionPerformed(ActionEvent event);}

Page 21: Lambdas: Myths and Mistakes

Functional InterfacesWant to support automated Data

Parallelism

Construct for building computation

pipelines

Iterator with inversion of control

Page 22: Lambdas: Myths and Mistakes

External Iterationint count = 0;for (Artist artist : artists) { if (artist.isFrom("London")) { count++; }}

Page 23: Lambdas: Myths and Mistakes

Internal Iterationartists.stream() .filter(artist -> artist.isFrom("London"));

Page 24: Lambdas: Myths and Mistakes

map

Page 25: Lambdas: Myths and Mistakes

mapList<String> collected = Stream.of("a", "b", "hello") .map(string -> string.toUpperCase()) .collect(toList());

assertEquals(asList("A", "B", "HELLO"),collected);

Page 26: Lambdas: Myths and Mistakes

reduce

Page 27: Lambdas: Myths and Mistakes

reduceint count = Stream.of(1, 2, 3) .reduce(0, (acc, x) -> acc + 1);

assertEquals(3, count);

Page 28: Lambdas: Myths and Mistakes

filter

Page 29: Lambdas: Myths and Mistakes

filterList<String> beginningWithNumbers = Stream.of("a", "1abc", "abc1") .filter(value -> isDigit(value.charAt(0))) .collect(toList());

assertEquals(asList("1abc"), beginningWithNumbers);

Page 30: Lambdas: Myths and Mistakes

Putting it all togetherfor a given an album, find the nationality of every band

playing on that album

Page 31: Lambdas: Myths and Mistakes

Putting it all together (2)1. transform an album into its artists2. figure out which artists are bands3. find the nationalities of each band

Page 32: Lambdas: Myths and Mistakes

Putting it all together (3)List<String> origins = album.getMusicians() .filter(artist -> artist.getName().startsWith("The")) .map(artist -> artist.getNationality()) .collect(toList());

Page 33: Lambdas: Myths and Mistakes

Method Referencesstr -> str.length

String::length

x -> foo.bar(x)foo::bar

str -> new Name(str)Name::new

Page 34: Lambdas: Myths and Mistakes

Beyond theMyths

Page 35: Lambdas: Myths and Mistakes

Claim: Syntax is the mostimportant thing aboutLambda Expressions

Page 36: Lambdas: Myths and Mistakes

Yeah, I liked the # syntax proposal better,too. One less character to type! :)

Page 37: Lambdas: Myths and Mistakes

Have you considered 'default null'? It willsave a keyword

Page 38: Lambdas: Myths and Mistakes

How about a single punctuation mark,currently unused, as syntax sugar for "()-

>".

Page 39: Lambdas: Myths and Mistakes

(_, _) -> _ + _

This is starting to look like risque ASCII art:)

Page 40: Lambdas: Myths and Mistakes

Its a Myth!

Page 41: Lambdas: Myths and Mistakes

Claim: Syntax is irrelevant

Page 42: Lambdas: Myths and Mistakes

// Originally invalidStream.of(1, 2, 3) .forEach(x -> System.out.println(x));

// Required extra ;Stream.of(1, 2, 3) .forEach(x -> System.out.println(x););

Page 43: Lambdas: Myths and Mistakes

Difference betweenexpectations

Many language features stolen! adapted

Missing Features

Stronger Type System

Tuples

List construction syntax

Page 44: Lambdas: Myths and Mistakes

Framing EffectDifferent reactions depending on whether something is

presented as a loss or a gain.

Page 45: Lambdas: Myths and Mistakes

Recall our earlier exampleList<String> origins = album.getMusicians() .filter(artist -> artist.getName().startsWith("The")) .map(artist -> artist.getNationality()) .collect(toList());

Page 46: Lambdas: Myths and Mistakes

Eager vs Lazy (2) album.getMusicians() .filter(artist -> artist.getName().startsWith("The")) .map(artist -> artist.getNationality())

Page 47: Lambdas: Myths and Mistakes

Eager vs Lazy (3) album.getMusicians() .filter(artist -> artist.getName().startsWith("The")) .map(artist -> artist.getNationality()) .collect(toList());

Page 48: Lambdas: Myths and Mistakes

Very little TDDOnly a couple of developers used TDD or

unit tests

Maybe a reflection on general TDD

Maybe unfamiliarity with testing

functional code

Page 49: Lambdas: Myths and Mistakes

How do I test this?list.stream() .map(x -> 1.0 / Math.ceil(1 + Math.pow(x) + Math.atan2(0, x))) .collect(toList());

Page 50: Lambdas: Myths and Mistakes

Approach 1: Testsurrounding function

Don't test the lambda

Test the method its surrounded by

Works well for simple lambdas

Page 51: Lambdas: Myths and Mistakes

Approach 2: ExtractMethod

double complexFunction(double x) { return 1.0 / Math.ceil(1 + Math.pow(x) + Math.atan2(0, x));}

list.stream() .map(this::complexFunction) .collect(toList());

Page 52: Lambdas: Myths and Mistakes

Mistake: debugginglist.stream() .filter(filteringFunction) .map(mappingFunction) .collect(toList());

List<Bar> bars = new ArrayList<>();for (Foo element : list) { if (filteringFunction(element) { Bar result = mappingFunction(element); bars.add(result); }}

Page 53: Lambdas: Myths and Mistakes

peeklist.stream() .filter(filteringFunction) .peek(e -> System.out.println("Filtered value: " + e)); .map(mappingFunction) .map(e -> e); .collect(toList());

Page 54: Lambdas: Myths and Mistakes

Compiler Error Messages

Page 55: Lambdas: Myths and Mistakes

ComparatorsComparator<String> comparator = comparing(String::length);

Comparator<String> comparator = comparing(str -> str.length);

Page 56: Lambdas: Myths and Mistakes

Compiler Errorjava: reference to comparing is ambiguous bothmethod<T>comparing(java.util.function.ToIntFunction< ? super T>)in java.util.Comparator and method<T,U>comparing(java.util.function.Function< ? super T,? extends U>)in java.util.Comparator match

Page 57: Lambdas: Myths and Mistakes

What happened?// Generic object variantpublic static <T, U extends Comparable< ? super U>> Comparator<T> comparing(Function< ? super T, ? extends U> keyExtractor)

// Specialised primitive variantpublic static <T> Comparator<T> comparing(ToIntFunction< ? super T> keyExtractor)

Page 58: Lambdas: Myths and Mistakes

SummarySyntax important, but not in the way

people think

New approaches for debugging and

testing

Take care of overloads and compiler

error messages

Page 59: Lambdas: Myths and Mistakes

FunctionalThinking

Page 60: Lambdas: Myths and Mistakes

FunctionalThinking?

Thinking in terms of the input to output relationship andnot a sequence of steps

Page 61: Lambdas: Myths and Mistakes

First code that peoplewrite

List<Integer> numbers = Arrays.asList(1, 2, 3);numbers.forEach(x -> { System.out.println(x);});

Page 62: Lambdas: Myths and Mistakes

Non-idiomatic ProposalsEg: capture non-final local variables

Page 63: Lambdas: Myths and Mistakes

Example ProblemCount the number of instances of each word in a

document.

Page 64: Lambdas: Myths and Mistakes

Example Problem

Page 65: Lambdas: Myths and Mistakes

Ideal Solutionreader.lines() .flatMap(s -> Stream.of(s.split(" "))) .collect(groupingBy(s -> s, counting()));

Page 66: Lambdas: Myths and Mistakes

Ideal Solution (then)reader.lines() .flatMap(s -> Stream.of(s.split(" "))) .collect(groupingBy(s -> s, reducing(s -> 1, Integer::sum)));

// Map entries for "dad"// [ "dad", "dad", "dad" ] => [1, 1, 1] => 3

Page 67: Lambdas: Myths and Mistakes

Bad Solution (Part 1)Map<string, list<string="">> initial = br.lines() .flatMap(s -> Arrays.stream(s.split(" "))) .collect(groupingBy(s -> s)); Map<map.entry<string, integer="">, Integer> freq1 = initial .entrySet().stream() .map(entry -> new AbstractMap.SimpleImmutableEntry<string, integer="">(entry.getKey(), entry.getValue().size())) .collect(Collectors.toMap(entry -> entry.getValue())); </string,></map.entry<string,></string,>

Page 68: Lambdas: Myths and Mistakes

Bad Solution (Part 2) Supplier<hashmap<string, integer="">> supplier = () -> newHashMap<string, integer="">(); BiConsumer<hashmap<string, integer="">, Map.Entry<string, integer="">> accum = (HashMap<string, integer=""> result, Map.Entry<string, integer="">entry) -> result.put(entry.getKey(), entry.getValue()); BiConsumer<hashmap<string, integer="">, HashMap<string, integer="">>merger = HashMap::putAll;

Map<string, integer=""> freq2 = initial.entrySet().stream() .map(entry -> new AbstractMap.SimpleImmutableEntry<string, integer="">(entry.getKey(), entry.getValue().size())) .collect(supplier, accum, merger); </string,></string,></string,></hashmap<string,></string,></string,

Page 69: Lambdas: Myths and Mistakes

SummaryFunctional Thinking the most important

thing to learn

Not Java specific at all

Requires Practise

Page 70: Lambdas: Myths and Mistakes

ConclusionsGone through a bunch of examples of

specific issues

‘Functional Thinking’: Not necessary to

start learning.

Try before you buy

Page 71: Lambdas: Myths and Mistakes

Questions?@RichardWarburto

http://insightfullogic.com

https://github.com/RichardWarburton/


Top Related