65
John Ferguson Smart [email protected] h2p://www.wakaleo.com Twi2er: wakaleo Improve Your Java Code, Functional-Style - Now!

Functional programming in java

Embed Size (px)

DESCRIPTION

Functional programming is all the rage. It can undoubtedly produce cleaner and more expressive code, but why switch to Scala or wait for Java 8? In fact, there are many ways to dramatically improve your Java code quality by using a more functional style today. This presentation discusses how techniques such as functional programming, using fluent APIs, and other clean coding practices can make your code more concise, more readable, and much easier to maintain. But more importantly, you will learn about libraries such as LambdaJ and Google Guava that make this possible today with your existing Java code base.

Citation preview

Page 1: Functional programming in java

John  Ferguson  [email protected]  h2p://www.wakaleo.com

Twi2er:  wakaleo

Improve Your Java Code, Functional-Style - Now!

Page 2: Functional programming in java

So who is this guy, anyway?

John Ferguson Smart

ConsultantTrainerMentorAuthorSpeakerCoder

Page 3: Functional programming in java

f(x,y) = x + y

Func:onal  Programming  is  the  new  black

Page 4: Functional programming in java

Immutability  is  your  friend

Page 5: Functional programming in java

Avoid  nasty  side-­‐effects

Page 6: Functional programming in java

Benefit  from  concurrency

Page 7: Functional programming in java

No  more  messy  loops

Page 8: Functional programming in java

HowWhat

Page 9: Functional programming in java

Func:onal  Programming  in  Java

Coming  to  a  JVM  near  you  the  summer  of  2013

Page 10: Functional programming in java

List<String> names = Arrays.asList("Aristotle", "Plato", "Socrates", "Pythagoras");

List<String> filteredNames = names       .filter(name -> name.startsWith("P"))       .into(new ArrayList<String>());

assertThat(filteredNames, contains("Plato", "Pythagoras"));

Java  8  supports  Lambda  Expressions

Page 11: Functional programming in java

names.filter(name -> name.startsWith("P"))     .into(new ArrayList<String>());

["Aristotle", "Plato", "Socrates", "Pythagoras"]

["Plato", "Pythagoras"]

Java  8  supports  Lambda  Expressions

Page 12: Functional programming in java

public class Pet {    private String name;    private Species species;

    Pet(String name, Species species) {...}

    public String getName() {...}    public Species getSpecies() {...}

    @Override    public boolean equals(Object o) {...}

    @Override    public int hashCode() {...}

    enum Species {        Cat,        Dog,        GuineaPig;        Pet called(String name) { return new Pet(name, this); }    }}

Java  8  supports  Lambda  Expressions

Page 13: Functional programming in java

public class Pet {    private String name;    private Species species;

    Pet(String name, Species species) {...}

    public String getName() {...}    public Species getSpecies() {...}

    @Override    public boolean equals(Object o) {...}

    @Override    public int hashCode() {...}

    enum Species {        Cat,        Dog,        GuineaPig;        Pet called(String name) { return new Pet(name, this); }    }}

List<Pet> pets = Arrays.asList(Cat.called("Ginger"),                               Dog.called("Spot"),                               GuineaPig.called("Fluffy"),                               Dog.called("Rover"));

List<Pet> sortedDogs = pets.filter(a -> a.getSpecies() == Dog)                           .sorted((a, b) -> a.getName().compareTo(b.getName()))                           .into(new ArrayList<Pet>());

assertThat(sortedDogs, contains(Dog.called("Rover"),         Dog.called("Spot")));

Java  8  supports  Lambda  Expressions

Page 14: Functional programming in java

pets.filter(a -> a.getSpecies() == Dog)    .sorted((a, b) -> a.getName().compareTo(b.getName()))    .into(new ArrayList<Pet>());

[Ginger, Spot, Fluffy, Rover]

[Rover, Spot]

Java  8  supports  Lambda  Expressions

Page 15: Functional programming in java

pets.filter(a -> a.getSpecies() == Dog) .map(e -> { return e.getName(); }) .sorted((a, b) -> a.compareTo(b))    .into(new ArrayList<Pet>());

[Ginger, Spot, Fluffy, Rover]

["Rover", "Spot"]

Java  8  supports  Lambda  Expressions

Page 16: Functional programming in java

Predicate<Pet> carnivores = (pet) -> (pet.getSpecies() == Dog || pet.getSpecies() == Cat);

List<Pet> carnivorousPets = pets.filter(carnivores).into(new ArrayList<Pet>());

[Ginger, Spot, Fluffy, Rover]

["Ginger", "Spot", "Rover"]

Java  8  supports  Lambda  Expressions

Page 17: Functional programming in java

pets.filter((pet) -> (pet.getSpecies() == Dog || pet.getSpecies() == Cat))    .into(new ArrayList<Pet>());

[Ginger, Spot, Fluffy, Rover]

["Ginger", "Spot", "Rover"]

Java  8  supports  Lambda  Expressions

Page 18: Functional programming in java

Java  8  supports  Lambda  Expressions

public class VetStay {    private Pet pet;    private Date startOfStay;    private String diagnosis;

    public VetStay(Pet pet, Date startOfStay, String diagnosis) {        this.pet = pet;        this.startOfStay = startOfStay;        this.diagnosis = diagnosis;    }}

List<VetStay> vetStays = pets.map(pet -> { return new VetStay(pet, new Date(), "sore paw");})

                             .into(new ArrayList<VetStay>());

Page 19: Functional programming in java

List<Pet> pets = Arrays.asList(Cat.called("Ginger"),        Dog.called("Spot"),        GuineaPig.called("Fluffy"),        Dog.called("Rover"));

assert pets.anyMatch(pet -> pet.getSpecies() == Dog)

Java  8  supports  Lambda  Expressions

Page 20: Functional programming in java

But  Func:onal  Programming  in  Java  today?

Surely  this  is  madness!

Page 21: Functional programming in java

Google Guava

Page 22: Functional programming in java

Defensive

Thread-safe

Efficient

Immutable  Collec:ons

Page 23: Functional programming in java

List<String> colors = ImmutableList.of("red", "green", "blue");

Creating an immutable list

Set<String> colors = ImmutableSet. of("red", "green", "blue");Set<String> myColors = ImmutableSet.copyOf(colors);

Creating an immutable copy

Immutable  Collec:ons

Page 24: Functional programming in java

No  more  returning  Null

“Null sucks.” - Doug Lea

“I call it my billion-dollar mistake.” - Sir Tony Hoare

Page 25: Functional programming in java

No  more  returning  Null

interface ClientService {    Client findByName(String name); }

What does a null return value mean?

No matching client found (but we were expecting one)?

No matching client found (but we’re cool with that)?

Something went wrong?

Page 26: Functional programming in java

No  more  returning  Null

Optional<Client> clientOptional = clientService.findByName("Smith");if (clientOptional.isPresent()) {    Client client = clientOptional.get();} else {    // No client was found}

interface ClientService {    Optional<Client> findByName(String name); }

Sometimes we might not return a client

This forces us to cater for this case in our code

Page 27: Functional programming in java

No  more  returning  Null

Color colorToUse = person.getFavoriteColor().or(Blue)

class Person {    Optional<Color> getFavoriteColor(); }

A person may not have a favorite color

If not, use Blue

Page 28: Functional programming in java

And  lots  of  other  stuff...

Page 29: Functional programming in java

No  more  returning  Null

interface ClientService {    Client findByName(String name); }

What does a null return value mean?

No matching client found (but we were expecting one)?

No matching client found (but we’re cool with that)?

Something went wrong?

Page 30: Functional programming in java

No  more  returning  Null

Optional<Client> clientOptional = clientService.findByName("Smith");if (clientOptional.isPresent()) {    Client client = clientOptional.get();} else {    // No client was found}

interface ClientService {    Optional<Client> findByName(String name); }

Sometimes we might not return a client

This forces us to cater for this case in our code

Page 31: Functional programming in java

No  more  returning  Null

Color colorToUse = person.getFavoriteColor().or(Blue)

class Person {    Optional<Color> getFavoriteColor(); }

A person may not have a favorite color

If not, use Blue

Page 32: Functional programming in java

– DSL for manipulating collections in a functional style– Replace loops with more concise and readable code

lambdaj

Page 33: Functional programming in java

filter

LambdaJ support many high level collection-related functions

sort

extract

aggregate

convert

group

Page 34: Functional programming in java

import static ch.lambdaj.Lambda.filter;import static org.hamcrest.Matchers.startsWith;...List<String> names = Arrays.asList("Aristotle", "Plato", "Socrates", "Pythagoras");

List<String> filteredNames = filter(startsWith("P"), names);

assertThat(filteredNames, contains("Plato", "Pythagoras"));

Filtering  in  LambdaJ

LambdaJ

Hamcrest

Page 35: Functional programming in java

filter(startsWith("P"), names)

["Aristotle", "Plato", "Socrates", "Pythagoras"]

["Plato", "Pythagoras"]

Filtering  in  LambdaJ

Page 36: Functional programming in java

List<String> filteredNames = new ArrayList<>();for(String name : names) {    if (name.startsWith("P")) {        filteredNames.add(name);    }}

Old-style Java

names.filter(name -> name.startsWith("P"))     .into(new ArrayList<String>());

Java 8

filter(startsWith("P"), names)

Lambda J

Filtering  in  LambdaJ

Page 37: Functional programming in java

List<Pet> pets = Arrays.asList(Cat.called("Ginger"),         Dog.called("Spot"),        GuineaPig.called("Fluffy"),         Dog.called("Rover"));

List<Pet> sortedDogs = filter(having(on(Pet.class).getSpecies(), is(Dog)), pets);

assertThat(sortedDogs, contains(Dog.called("Rover"), Dog.called("Spot")));

Filtering  in  LambdaJ

Page 38: Functional programming in java

Filtering  in  LambdaJ

filter(having(on(Pet.class).getSpecies(), is(Dog)), pets);

[Ginger, Spot, Fluffy, Rover]

[Rover, Spot]

Page 39: Functional programming in java

Sor:ng  in  LambdaJ

sort(sortedDogs, on(Pet.class).getName());

[Ginger, Spot, Fluffy, Rover]

[Fluffy, Ginger, Rover, Spot]

Page 40: Functional programming in java

Filtering  and  Sor:ng  in  LambdaJ

List<Pet> filteredDogs = filter(having(on(Pet.class).getSpecies(), is(Dog)), pets);List<Pet> sortedDogs = sort(filteredDogs, on(Pet.class).getName());

[Ginger, Spot, Fluffy, Rover]

[Rover, Spot]

Page 41: Functional programming in java

Extrac:ng  in  LambdaJ

pets.filter(a -> a.getSpecies() == Dog) .map(e -> { return e.getName(); }) .sorted((a, b) -> a.compareTo(b))    .into(new ArrayList<Pet>());

[Ginger, Spot, Fluffy, Rover]

["Rover", "Spot"]

Extracting with Java 8

Page 42: Functional programming in java

Extrac:ng  in  LambdaJ

List<Pet> dogs = filter(having(on(Pet.class).getSpecies(), is(Dog)), pets);List<String> dogNames = extract(dogs, on(Pet.class).getName());List<String> sortedDogNames = sort(dogNames,on(String.class));

[Ginger, Spot, Fluffy, Rover]

["Rover", "Spot"]

Extracting with LambdaJ

Page 43: Functional programming in java

Extrac:ng  in  LambdaJ

[Ginger, Spot, Fluffy, Rover]

["Rover", "Spot"]

List<Pet> filteredDogs = new ArrayList();for(Pet pet : pets) {    if (pet.getSpecies() == Dog) {        filteredDogs.add(pet);    }}Collections.sort(filteredDogs, new Comparator<Pet>() {    @Override    public int compare(Pet pet, Pet pet1) {        return pet.getName().compareTo(pet1.getName());    }});

Extracting with old-style Java

Page 44: Functional programming in java

Extrac:ng  in  LambdaJ

List<Pet> dogs = filter(having(on(Pet.class).getSpecies(), is(Dog)), pets);List<String> dogNames = extract(dogs, on(Pet.class).getName());List<String> sortedDogNames = sort(dogNames,on(String.class));

[Ginger, Spot, Fluffy, Rover]

["Rover", "Spot"]

Extracting with LambdaJ

Page 45: Functional programming in java

Conver:ng  in  LambdaJ

List<VetStay> vetStays = pets.map(pet -> { return new VetStay(pet, new Date(), "sore paw");})                             .into(new ArrayList<VetStay>());

Converting with Java 8

convert(pets, toVetStay());

private Converter<Pet, VetStay> toVetStay() {    return new Converter<Pet, VetStay>() {        @Override        public VetStay convert(Pet pet) {            return new VetStay(pet, new Date(), "sore paw");        }    };}

Converting with LambdaJ

Page 46: Functional programming in java

Grouping  in  LambdaJ

Group<Pet> petsBySpecies = group(pets, by(on(Pet.class).getSpecies()));

List<Pet> dogs = petsBySpecies.find(Dog);

[Ginger, Spot, Fluffy, Rover]

[Spot,Rover]

Page 47: Functional programming in java

FlaOening  in  LambdaJ

List<List<Pet>> petsBySpecies = ...

List<Pet> allPets = flatten(petsBySpecies);

[[Spot, Rover], [Ginger], [Fluffy]]

[Spot, Rover, Ginger, Fluffy]

Page 48: Functional programming in java

Checking  existence  in  LambdaJ

exists(pets, having(on(Pet.class).getSpecies(), is(Cat)))

[Spot, Rover, Ginger, Fluffy]

true

Page 49: Functional programming in java

Using  Predicates  in  LambdaJ

Predicate<Pet> carnivores = (pet) -> (pet.getSpecies() == Dog || pet.getSpecies() == Cat);

List<Pet> carnivorousPets = pets.filter(carnivores).into(new ArrayList<Pet>());

Java 8

Matcher<Pet> carnivore = new Predicate<Pet>() {    public boolean apply(Pet pet) {        return (pet.getSpecies() == Dog || pet.getSpecies() == Cat);    }};

List<Pet> carnivores = filter(carnivore, pets);LambdaJ

Page 50: Functional programming in java

Using  Aggregates  in  LambdaJ

List<Pet> pets = Arrays.asList(Cat.called("Ginger"),        Dog.called("Spot"),        GuineaPig.called("Fluffy"),        Dog.called("Rover"));

int ageOfOldestPet = maxFrom(pets).getAge();int ageOfYoungestPet = minFrom(pets).getAge();int totalPetAges = sumFrom(pets).getAge();

Page 51: Functional programming in java

Some  real-­‐world  examples

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

FAILURE

TestOutcome  3

PENDING

TestOutcome  4

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

Page 52: Functional programming in java

Some  real-­‐world  examples

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

FAILURE

TestOutcome  3

PENDING

TestOutcome  4

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

filter(having(on(TestOutcome.class).getResult(), is(SUCCESS)), outcomes);

Page 53: Functional programming in java

Some  real-­‐world  examples

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

FAILURE

TestOutcome  3

PENDING

TestOutcome  4

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

filter(withResult(SUCCESS)), outcomes);

private Matcher<?> withResult(TestResult expectedResult) {    return having(on(TestOutcome.class).getResult(), is(expectedResult));}

Page 54: Functional programming in java

Some  real-­‐world  examples

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

FAILURE

TestOutcome  3

PENDING

TestOutcome  4

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

filter(anyOf(withResult(SUCCESS), withResult(PENDING)), outcomes);

PENDING

TestOutcome  4

Page 55: Functional programming in java

Some  real-­‐world  examples

SUCCESS

TestOutcome  1

SUCCESS

TestOutcome  2

FAILURE

TestOutcome  3

PENDING

TestOutcome  4

TestOutcome  2

Step  1

Step  2

Step  3

Step  4

Page 56: Functional programming in java

Some  real-­‐world  examples

TagProvider1

TagProvider2

TagTag 1Tag

TagTagTagTag

TagTag 1TagTagTagTagTag

flatten(extract(TagProviders, on(TagProvider.class).getTags()));

Page 57: Functional programming in java

And  performance  in  all  that?

Page 58: Functional programming in java

Keeping  things  maintainable

“Excessive use of Guava's functional programming idioms can lead to verbose, confusing, unreadable, and inefficient code.” - the Guava team

Can also be true of LambdaJ

Page 59: Functional programming in java

Keeping  things  maintainable

RULE 1

Use a functional style when it makes the intent more readable

Page 60: Functional programming in java

Keeping  things  maintainable

sort(extract(filter(having(on(Pet.class).getSpecies(), is(Dog)), pets), on(Pet.class).getName()), on(String.class));

List<Pet> dogs = filter(having(on(Pet.class).getSpecies(), is(Dog)), pets);List<String> dogNames = extract(dogs, on(Pet.class).getName());List<String> sortedDogNames = sort(dogNames, on(String.class));

Page 61: Functional programming in java

Keeping  things  maintainable

RULE 2

One-liners are not always better

Page 62: Functional programming in java

Keeping  things  maintainable

convert(pets,        new Converter<Pet, VetStay>() {                    @Override                    public VetStay convert(Pet pet) {                        return new VetStay(pet, new Date(), "sore paw");                    }        });

convert(pets, toVetStay());

private Converter<Pet, VetStay> toVetStay() {    return new Converter<Pet, VetStay>() {        @Override        public VetStay convert(Pet pet) {            return new VetStay(pet, new Date(), "sore paw");        }    };}

Page 63: Functional programming in java

Keeping  things  maintainable

RULE 3

Write your own domain-specific matchers

Page 64: Functional programming in java

Keeping  things  maintainable

filter(withResult(SUCCESS)), outcomes);

private Matcher<?> withResult(TestResult expectedResult) {    return having(on(TestOutcome.class).getResult(), is(expectedResult));}

select(anyOf(withResult(SKIPPED), withResult(IGNORED)), outcomes);

select(not(withResult(SUCCESS))), outcomes);

Page 65: Functional programming in java

John  Ferguson  [email protected]  h2p://www.wakaleo.com

Twi2er:  wakaleo

Thank You