SlideShare una empresa de Scribd logo
1 de 66
Descargar para leer sin conexión
Pragmatic Functional
Refactoring with Java 8
Raoul-Gabriel Urma (@raoulUK)
Richard Warburton (@RichardWarburto)
First-class Functions
Currying
Immutability
Optional Data Types
Conclusions
Step 1: filtering invoices from Oracle
public List<Invoice> findInvoicesFromOracle(List<Invoice> invoices) {
List<Invoice> result = new ArrayList<>();
for(Invoice invoice: invoices) {
if(invoice.getCustomer() == Customer.ORACLE) {
result.add(invoice);
}
}
return result;
}
Step 2a: abstracting the customer
public List<Invoice> findInvoicesFromCustomer(List<Invoice> invoices,
Customer customer) {
List<Invoice> result = new ArrayList<>();
for(Invoice invoice: invoices) {
if(invoice.getCustomer() == customer) {
result.add(invoice);
}
}
return result;
}
Step 2b: abstracting the name
public List<Invoice> findInvoicesEndingWith(List<Invoice> invoices,
String suffix) {
List<Invoice> result = new ArrayList<>();
for(Invoice invoice: invoices) {
if(invoice.getName().endsWith(suffix)) {
result.add(invoice);
}
}
return result;
}
Step 3: messy code-reuse!
private List<Invoice> findInvoices(List<Invoice> invoices,
Customer customer,
String suffix,
boolean flag) {
List<Invoice> result = new ArrayList<>();
for(Invoice invoice: invoices) {
if((flag && invoice.getCustomer() == customer)
|| (!flag && invoice.getName().endsWith(suffix))) {
result.add(invoice);
}
}
return result;
}
Step 4a: modeling the filtering criterion
public interface Predicate<T> {
boolean test(T t);
}
Invoice boolean
Predicate<Invoice>
Step 4b: using different criterion with objects
private List<Invoice> findInvoices(List<Invoice> invoices,
Predicate<Invoice> p) {
List<Invoice> result = new ArrayList<>();
for(Invoice invoice: invoices) {
if(p.test(invoice)) {
result.add(invoice);
}
}
return result;
}
Step 4b: using different criterion with objects
List<Invoice> specificInvoices =
findInvoices(invoices, new FacebookTraining());
class FacebookTraining implements Predicate<Invoice> {
@Override
public boolean test(Invoice invoice) {
return invoice.getCustomer() == Customer.FACEBOOK
&& invoice.getName().endsWith("Training");
}
}
Step 5: method references
public boolean isOracleInvoice(Invoice invoice) {
return invoice.getCustomer() == Customer.ORACLE;
}
public boolean isTrainingInvoice(Invoice invoice) {
return invoice.getName().endsWith("Training");
}
List<Invoice> oracleInvoices =
findInvoices(invoices, this::isOracleInvoice);
List<Invoice> trainingInvoices =
findInvoices(invoices, this::isTrainingInvoice);
method references
Step 6: lambdas
List<Invoice> oracleInvoices =
findInvoices(invoices,
invoice -> invoice.getCustomer() == Customer.ORACLE);
List<Invoice> trainingInvoices =
findInvoices(invoices,
invoice -> invoice.getName().endsWith("Training"));
First-class functions
● Common Object Oriented concept: Function Object
● All it means is the ability to use a function just like a regular value
○ Pass it as argument to a method
○ Store it in a variable
● Helps cope with requirement changes
Composing functions
Functions Composing functions
Composing functions: example
import java.util.function.Predicate;
Predicate<Invoice> isFacebookInvoice = this::isFacebookInvoice;
List<Invoice> facebookAndTraining =
invoices.stream()
.filter( isFacebookInvoice.and(this::isTrainingInvoice))
.collect(toList());
List<Invoice> facebookOrGoogle =
invoices.stream()
.filter( isFacebookInvoice.or(this::isGoogleInvoice))
.collect(toList());
creating more complex
functions from building blocks
Composing functions: why does it work?
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
}
returns a new
function that is
the result of
composing two
functions
Creating function pipelines (1)
public class Email {
private final String message;
public Email(String message) {
this.message = message;
}
public Email addHeader() {
return new Email("Dear Sir/Madam:n" + message);
}
public Email checkSpelling() {
return new Email(message.replaceAll("FTW", "for the win"));
}
public Email addSignature() {
return new Email(message + "nKind regards");
}
}
Creating function pipelines (2)
import java.util.function.Function;
Function<Email, Email> addHeader = Email::addHeader;
Function<Email, Email> processingPipeline =
addHeader.andThen(Email::checkSpelling)
.andThen(Email::addSignature);
addHeader checkSpelling addSignature
andThen andThen
Email
{message="Java
8 FTW!"}
Email{message='Dear
Sir/Madam:
Java 8 for the win!
Kind regards'}
composing
functions
Creating function pipelines (3)
import java.util.function.Function;
Function<Email, Email> addHeader = Email::addHeader;
Function<Email, Email> processingPipeline =
addHeader.andThen(Email::addSignature);
addHeader addSignature
andThen
Email
{message="Java
8 FTW!"}
Email{message='Dear
Sir/Madam:
Java 8 FTW!
Kind regards'}
composing
functions
First-class Functions
Currying
Immutability
Optional Data Types
Conclusions
Example: A Conversion Function
double convert(double amount, double factor, double base)
{
return amount * factor + base;
}
// Usage
double result = convert(10, 1.8, 32);
assertEquals(result, 50, 0.0);
Using the conversion function
// Temperatures
double cInF = convert(10, 1.8, 32);
double higherTemp = convert(30, 1.8, 32);
// Currencies
double dollarsInPounds = convert(10, 0.6, 0);
// Distance
double kilometresInMiles = convert(27, 0.62137, 0);
So what’s the problem?
● Abstraction
○ How do you write something that operates on different conversion
functions?
● Reuse
○ How do you use the conversion function in different places?
Currying the conversion function
double convert(double amount, double factor, double base) {
return amount * factor + base;
}
DoubleUnaryOperator convert(double factor, double base) {
return amount -> amount * factor + base;
}
Using the conversion function
DoubleUnaryOperator convert(double factor, double base) {
return amount -> amount * factor + base;
}
DoubleUnaryOperator convertCtoF = convert(1.8, 32);
double result = convertCtoF.applyAsDouble(10);
assertEquals(result, 50, 0.0);
Partial Application Examples
// Temperatures
DoubleUnaryOperator convertCtoF = convert(1.8, 32);
// Currencies
DoubleUnaryOperator convert$to£ = convert(0.6, 0);
// Distance
DoubleUnaryOperator convertKmToMi = convert(0.62137, 0);
Definition
// int -> (int -> int)
IntFunction<IntUnaryOperator>
curry(IntBinaryOperator biFunction) {
return f -> (s -> biFunction.applyAsInt(f, s));
}
Usage
IntFunction<IntUnaryOperator> add
= curry((f, s) -> f + s);
int result = add.apply(1)
.applyAsInt(2);
assertEquals(3, result);
Example currying use cases
● Large factory methods
○ Partially apply some of the arguments and then pass this factory
object around.
● Combinators libraries
○ Parsers
○ HTML templating
Summary
● Currying is about splitting up the arguments of a function.
● Partial Application is a function “eating” some of its arguments and
returning a new function
First-class Functions
Currying
Immutability
Optional Data Types
Conclusions
Mutable objects
public class TrainJourney {
private int price;
private TrainJourney onward;
public TrainJourney(int price, TrainJourney onward) {
this.price = price;
this.onward = onward;
}
public int getPrice() {
return price;
}
public TrainJourney getOnward() {
return onward;
}
public void setPrice(int price) {
this.price = price;
}
public void setOnward(TrainJourney onward) {
this.onward = onward;
}
}
Immutable objects
public final class TrainJourneyImmutable {
private final int price;
private final TrainJourneyImmutable onward;
public TrainJourneyImmutable(int price, TrainJourney onward) {
this.price = price;
this.onward = onward;
}
public int getPrice() {
return price;
}
public TrainJourneyImmutable getOnward() {
return onward;
}
public TrainJourneyImmutable withPrice(int price) {
return new TrainJourneyImmutable(price, getOnward());
}
public TrainJourneyImmutable withOnward(TrainJourneyImmutable onward) {
return new TrainJourneyImmutable(getPrice(), onward);
}
}
Scenario: be able to link together train
journeys to form longer journeys.
Mutable approach
public TrainJourney link(TrainJourney start, TrainJourney continuation) {
if (start == null) {
return continuation;
}
TrainJourney t = start;
while (t.getOnward() != null) {
t = t.getOnward();
}
t.setOnward(continuation);
return start;
}
find the last stop in the first journey
modify it to link to the continuation
journey
return the continuation journey if
there is no start journey
Mutable approach: problem
TrainJourney firstJourney = link(start, continuation);
TrainJourney secondJourney = link(start, continuation);
visit(secondJourney,
tj -> { System.out.print(tj.price + " - "); });
static void visit(TrainJourney journey, Consumer<TrainJourney> c)
{
if (journey != null) {
c.accept(journey);
visit(journey.onward, c);
}
}
java.lang.StackOverflowError
Immutable approach
public TrainJourneyImmutable link(TrainJourneyImmutable start,
TrainJourneyImmutable continuation) {
return start == null ? continuation
: new TrainJourneyImmutable(start.getPrice(),
link(start.getOnward(), continuation));
}
Related topics
● Domain Driven Design
○ Value Classes are Immutable
● Core Java Improvements
○ New date & time library in Java 8 has many Immutable Objects
○ Current Value Types proposal is immutable
● Tooling
○ final keyword only bans reassignment
○ JSR 308 - improved annotation opportunities
○ Mutability Detector
○ Findbugs
Downsides to Immutability
● Increased memory allocation pressure
● Some problems harder to model with immutability
○ Deep object graphs
○ Example: Car simulation
● Library interactions
○ ORMs especially
○ Serialisation usually ok these days
● Alternative: small blobs of simple and localised state
Immutable objects reduce the scope for bugs.
First-class Functions
Currying
Immutability
Optional Data Types
Conclusions
Don’t we all love it?
Exception in thread "main" java.lang.NullPointerException
public String getCarInsuranceName(Person person) {
return person.getCar().getInsurance().getName();
}
Where’s the NPE?
Defensive checking
public String getCarInsuranceName(Person person) {
if (person != null) {
Car car = person.getCar();
if (car != null) {
Insurance insurance = car.getInsurance();
if (insurance != null) {
return insurance.getName();
}
}
}
return "No Insurance";
}
Optional
● Java 8 introduces a new class java.util.Optional<T>
○ a single-value container
● Explicit modelling
○ Immediately clear that its an optional value
○ better maintainability
● You need to actively unwrap an Optional
○ force users to think about the absence case
○ fewer errors
Updating model
public class Person {
private Optional<Car> car;
public Optional<Car> getCar() { return car; }
}
public class Car {
private Optional<Insurance> insurance;
public Optional<Insurance> getInsurance() { return insurance; }
}
public class Insurance {
private String name;
public String getName() { return name; }
}
Optional.map
Why it doesn’t work?
Optional<People> optPerson = Optional.ofNullable(person);
Optional<String> name =
optPeople.map(Person::getCar)
.map(Car::getInsurance)
.map(Insurance::getName);
returns Optional<Optional<Car>>
Invalid, the inner Optional object
doesn’t support the method
getInsurance!
public class Person {
private Optional<Car> car;
public Optional<Car> getCar() { return car; }
}
Optional.flatMap
Chaining methods with flatMap
public String getCarInsuranceName(Person person) {
return Optional.ofNullable(person)
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
default value if the resulting
Optional is empty
A comment on naming
public String getCarInsuranceName(Person person) {
Set<Person> personSet = person == null
? emptySet()
: singleton(person);
return personSet.stream()
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
Optional in Fields
● Should it be used for fields, or just public methods?
● Pros
○ Explicit modelling
○ Null-safe access
○ Simple getters
● Cons
○ More indirection and GC overhead in Java 8
○ Not every library understands Optional yet
○ Some libraries require Serializable fields
Consistent use of Optional replaces the use of null
First-class Functions
Currying
Immutability
Optional Data Types
Conclusions
Summary of benefits
● First-class functions let you cope for requirement changes
● Currying lets you split the parameters of a function to re-use code logic
● Immutability reduces the scope for bugs
● Optional data types lets you reduce null checking boilerplate and
prevent bugs
http://java8training.com
http://manning.com/urma http://tinyurl.com/java8lambdas
Any Questions?
Richard Warburton
@richardwarburto
Raoul-Gabriel Urma
@raoulUK
Generalised curry function
// F -> (S -> R)
<F, S, R> Function<F, Function<S, R>>
curry(BiFunction<F, S, R> biFunction) {
return f -> s -> biFunction.apply(f, s);
}

Más contenido relacionado

La actualidad más candente

Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Mario Fusco
 
FP 201 - Unit 6
FP 201 - Unit 6FP 201 - Unit 6
FP 201 - Unit 6
rohassanie
 
FP 201 - Unit 3 Part 2
FP 201 - Unit 3 Part 2FP 201 - Unit 3 Part 2
FP 201 - Unit 3 Part 2
rohassanie
 

La actualidad más candente (20)

Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
Scala is java8.next()
Scala is java8.next()Scala is java8.next()
Scala is java8.next()
 
The underestimated power of KeyPaths
The underestimated power of KeyPathsThe underestimated power of KeyPaths
The underestimated power of KeyPaths
 
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...Map(), flatmap() and reduce() are your new best friends: simpler collections,...
Map(), flatmap() and reduce() are your new best friends: simpler collections,...
 
Fp201 unit5 1
Fp201 unit5 1Fp201 unit5 1
Fp201 unit5 1
 
Fp201 unit4
Fp201 unit4Fp201 unit4
Fp201 unit4
 
FP 201 - Unit 6
FP 201 - Unit 6FP 201 - Unit 6
FP 201 - Unit 6
 
Unlocking the Magic of Monads with Java 8
Unlocking the Magic of Monads with Java 8Unlocking the Magic of Monads with Java 8
Unlocking the Magic of Monads with Java 8
 
Jumping-with-java8
Jumping-with-java8Jumping-with-java8
Jumping-with-java8
 
classes & objects in cpp overview
classes & objects in cpp overviewclasses & objects in cpp overview
classes & objects in cpp overview
 
Functional Programming
Functional ProgrammingFunctional Programming
Functional Programming
 
Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)Composing an App with Free Monads (using Cats)
Composing an App with Free Monads (using Cats)
 
FP 201 - Unit 3 Part 2
FP 201 - Unit 3 Part 2FP 201 - Unit 3 Part 2
FP 201 - Unit 3 Part 2
 
Java PRACTICAL file
Java PRACTICAL fileJava PRACTICAL file
Java PRACTICAL file
 
6. Generics. Collections. Streams
6. Generics. Collections. Streams6. Generics. Collections. Streams
6. Generics. Collections. Streams
 
Generics in .NET, C++ and Java
Generics in .NET, C++ and JavaGenerics in .NET, C++ and Java
Generics in .NET, C++ and Java
 
The Ring programming language version 1.4.1 book - Part 9 of 31
The Ring programming language version 1.4.1 book - Part 9 of 31The Ring programming language version 1.4.1 book - Part 9 of 31
The Ring programming language version 1.4.1 book - Part 9 of 31
 
The Ring programming language version 1.5.1 book - Part 30 of 180
The Ring programming language version 1.5.1 book - Part 30 of 180The Ring programming language version 1.5.1 book - Part 30 of 180
The Ring programming language version 1.5.1 book - Part 30 of 180
 
Intro to Functional Programming
Intro to Functional ProgrammingIntro to Functional Programming
Intro to Functional Programming
 
Class method
Class methodClass method
Class method
 

Destacado

Destacado (7)

How to run a hackday
How to run a hackdayHow to run a hackday
How to run a hackday
 
Performance and predictability
Performance and predictabilityPerformance and predictability
Performance and predictability
 
Java collections the force awakens
Java collections  the force awakensJava collections  the force awakens
Java collections the force awakens
 
Generics Past, Present and Future
Generics Past, Present and FutureGenerics Past, Present and Future
Generics Past, Present and Future
 
Twins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional ProgrammingTwins: Object Oriented Programming and Functional Programming
Twins: Object Oriented Programming and Functional Programming
 
Jvm profiling under the hood
Jvm profiling under the hoodJvm profiling under the hood
Jvm profiling under the hood
 
Performance and predictability (1)
Performance and predictability (1)Performance and predictability (1)
Performance and predictability (1)
 

Similar a Pragmatic functional refactoring with java 8 (1)

Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
ShriKant Vashishtha
 
Design patterns in the 21st Century
Design patterns in the 21st CenturyDesign patterns in the 21st Century
Design patterns in the 21st Century
Samir Talwar
 
This is a C# project . I am expected to create as this image shows. .pdf
This is a C# project . I am expected to create as this image shows. .pdfThis is a C# project . I am expected to create as this image shows. .pdf
This is a C# project . I am expected to create as this image shows. .pdf
indiaartz
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimized
Woody Pewitt
 

Similar a Pragmatic functional refactoring with java 8 (1) (20)

From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
Design patterns in the 21st Century
Design patterns in the 21st CenturyDesign patterns in the 21st Century
Design patterns in the 21st Century
 
Operator overloading
Operator overloadingOperator overloading
Operator overloading
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
 
Recompacting your react application
Recompacting your react applicationRecompacting your react application
Recompacting your react application
 
react-hooks.pdf
react-hooks.pdfreact-hooks.pdf
react-hooks.pdf
 
This is a C# project . I am expected to create as this image shows. .pdf
This is a C# project . I am expected to create as this image shows. .pdfThis is a C# project . I am expected to create as this image shows. .pdf
This is a C# project . I am expected to create as this image shows. .pdf
 
JS Fest 2019. Glenn Reyes. With great power comes great React hooks!
JS Fest 2019. Glenn Reyes. With great power comes great React hooks!JS Fest 2019. Glenn Reyes. With great power comes great React hooks!
JS Fest 2019. Glenn Reyes. With great power comes great React hooks!
 
Being Functional on Reactive Streams with Spring Reactor
Being Functional on Reactive Streams with Spring ReactorBeing Functional on Reactive Streams with Spring Reactor
Being Functional on Reactive Streams with Spring Reactor
 
React JS Hooks Sheet .pdf
React JS Hooks Sheet .pdfReact JS Hooks Sheet .pdf
React JS Hooks Sheet .pdf
 
Gwt and Xtend
Gwt and XtendGwt and Xtend
Gwt and Xtend
 
How to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescriptHow to build to do app using vue composition api and vuex 4 with typescript
How to build to do app using vue composition api and vuex 4 with typescript
 
Powering code reuse with context and render props
Powering code reuse with context and render propsPowering code reuse with context and render props
Powering code reuse with context and render props
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at Pinterest
 
Design Patterns in the 21st Century - Samir Talwar
Design Patterns in the 21st Century - Samir TalwarDesign Patterns in the 21st Century - Samir Talwar
Design Patterns in the 21st Century - Samir Talwar
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimized
 
Refactoring
RefactoringRefactoring
Refactoring
 
Higher Order Components and Render Props
Higher Order Components and Render PropsHigher Order Components and Render Props
Higher Order Components and Render Props
 

Más de RichardWarburton

Más de RichardWarburton (20)

Fantastic performance and where to find it
Fantastic performance and where to find itFantastic performance and where to find it
Fantastic performance and where to find it
 
Production profiling what, why and how technical audience (3)
Production profiling  what, why and how   technical audience (3)Production profiling  what, why and how   technical audience (3)
Production profiling what, why and how technical audience (3)
 
Production profiling: What, Why and How
Production profiling: What, Why and HowProduction profiling: What, Why and How
Production profiling: What, Why and How
 
Production profiling what, why and how (JBCN Edition)
Production profiling  what, why and how (JBCN Edition)Production profiling  what, why and how (JBCN Edition)
Production profiling what, why and how (JBCN Edition)
 
Production Profiling: What, Why and How
Production Profiling: What, Why and HowProduction Profiling: What, Why and How
Production Profiling: What, Why and How
 
Generics Past, Present and Future (Latest)
Generics Past, Present and Future (Latest)Generics Past, Present and Future (Latest)
Generics Past, Present and Future (Latest)
 
Collections forceawakens
Collections forceawakensCollections forceawakens
Collections forceawakens
 
Generics past, present and future
Generics  past, present and futureGenerics  past, present and future
Generics past, present and future
 
Introduction to lambda behave
Introduction to lambda behaveIntroduction to lambda behave
Introduction to lambda behave
 
Introduction to lambda behave
Introduction to lambda behaveIntroduction to lambda behave
Introduction to lambda behave
 
Performance and predictability
Performance and predictabilityPerformance and predictability
Performance and predictability
 
Simplifying java with lambdas (short)
Simplifying java with lambdas (short)Simplifying java with lambdas (short)
Simplifying java with lambdas (short)
 
Twins: OOP and FP
Twins: OOP and FPTwins: OOP and FP
Twins: OOP and FP
 
Twins: OOP and FP
Twins: OOP and FPTwins: OOP and FP
Twins: OOP and FP
 
The Bleeding Edge
The Bleeding EdgeThe Bleeding Edge
The Bleeding Edge
 
Lambdas myths-and-mistakes
Lambdas myths-and-mistakesLambdas myths-and-mistakes
Lambdas myths-and-mistakes
 
Caching in
Caching inCaching in
Caching in
 
Lambdas: Myths and Mistakes
Lambdas: Myths and MistakesLambdas: Myths and Mistakes
Lambdas: Myths and Mistakes
 
Better than a coin toss
Better than a coin tossBetter than a coin toss
Better than a coin toss
 
Devoxx uk lambdas hackday
Devoxx uk lambdas hackdayDevoxx uk lambdas hackday
Devoxx uk lambdas hackday
 

Último

Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Victor Rentea
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 

Último (20)

Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
Modular Monolith - a Practical Alternative to Microservices @ Devoxx UK 2024
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUKSpring Boot vs Quarkus the ultimate battle - DevoxxUK
Spring Boot vs Quarkus the ultimate battle - DevoxxUK
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 

Pragmatic functional refactoring with java 8 (1)

  • 1. Pragmatic Functional Refactoring with Java 8 Raoul-Gabriel Urma (@raoulUK) Richard Warburton (@RichardWarburto)
  • 2.
  • 3.
  • 5. Step 1: filtering invoices from Oracle public List<Invoice> findInvoicesFromOracle(List<Invoice> invoices) { List<Invoice> result = new ArrayList<>(); for(Invoice invoice: invoices) { if(invoice.getCustomer() == Customer.ORACLE) { result.add(invoice); } } return result; }
  • 6. Step 2a: abstracting the customer public List<Invoice> findInvoicesFromCustomer(List<Invoice> invoices, Customer customer) { List<Invoice> result = new ArrayList<>(); for(Invoice invoice: invoices) { if(invoice.getCustomer() == customer) { result.add(invoice); } } return result; }
  • 7. Step 2b: abstracting the name public List<Invoice> findInvoicesEndingWith(List<Invoice> invoices, String suffix) { List<Invoice> result = new ArrayList<>(); for(Invoice invoice: invoices) { if(invoice.getName().endsWith(suffix)) { result.add(invoice); } } return result; }
  • 8. Step 3: messy code-reuse! private List<Invoice> findInvoices(List<Invoice> invoices, Customer customer, String suffix, boolean flag) { List<Invoice> result = new ArrayList<>(); for(Invoice invoice: invoices) { if((flag && invoice.getCustomer() == customer) || (!flag && invoice.getName().endsWith(suffix))) { result.add(invoice); } } return result; }
  • 9. Step 4a: modeling the filtering criterion public interface Predicate<T> { boolean test(T t); } Invoice boolean Predicate<Invoice>
  • 10. Step 4b: using different criterion with objects private List<Invoice> findInvoices(List<Invoice> invoices, Predicate<Invoice> p) { List<Invoice> result = new ArrayList<>(); for(Invoice invoice: invoices) { if(p.test(invoice)) { result.add(invoice); } } return result; }
  • 11. Step 4b: using different criterion with objects List<Invoice> specificInvoices = findInvoices(invoices, new FacebookTraining()); class FacebookTraining implements Predicate<Invoice> { @Override public boolean test(Invoice invoice) { return invoice.getCustomer() == Customer.FACEBOOK && invoice.getName().endsWith("Training"); } }
  • 12. Step 5: method references public boolean isOracleInvoice(Invoice invoice) { return invoice.getCustomer() == Customer.ORACLE; } public boolean isTrainingInvoice(Invoice invoice) { return invoice.getName().endsWith("Training"); } List<Invoice> oracleInvoices = findInvoices(invoices, this::isOracleInvoice); List<Invoice> trainingInvoices = findInvoices(invoices, this::isTrainingInvoice); method references
  • 13. Step 6: lambdas List<Invoice> oracleInvoices = findInvoices(invoices, invoice -> invoice.getCustomer() == Customer.ORACLE); List<Invoice> trainingInvoices = findInvoices(invoices, invoice -> invoice.getName().endsWith("Training"));
  • 14. First-class functions ● Common Object Oriented concept: Function Object ● All it means is the ability to use a function just like a regular value ○ Pass it as argument to a method ○ Store it in a variable ● Helps cope with requirement changes
  • 16. Composing functions: example import java.util.function.Predicate; Predicate<Invoice> isFacebookInvoice = this::isFacebookInvoice; List<Invoice> facebookAndTraining = invoices.stream() .filter( isFacebookInvoice.and(this::isTrainingInvoice)) .collect(toList()); List<Invoice> facebookOrGoogle = invoices.stream() .filter( isFacebookInvoice.or(this::isGoogleInvoice)) .collect(toList()); creating more complex functions from building blocks
  • 17. Composing functions: why does it work? public interface Predicate<T> { boolean test(T t); default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } } returns a new function that is the result of composing two functions
  • 18. Creating function pipelines (1) public class Email { private final String message; public Email(String message) { this.message = message; } public Email addHeader() { return new Email("Dear Sir/Madam:n" + message); } public Email checkSpelling() { return new Email(message.replaceAll("FTW", "for the win")); } public Email addSignature() { return new Email(message + "nKind regards"); } }
  • 19. Creating function pipelines (2) import java.util.function.Function; Function<Email, Email> addHeader = Email::addHeader; Function<Email, Email> processingPipeline = addHeader.andThen(Email::checkSpelling) .andThen(Email::addSignature); addHeader checkSpelling addSignature andThen andThen Email {message="Java 8 FTW!"} Email{message='Dear Sir/Madam: Java 8 for the win! Kind regards'} composing functions
  • 20. Creating function pipelines (3) import java.util.function.Function; Function<Email, Email> addHeader = Email::addHeader; Function<Email, Email> processingPipeline = addHeader.andThen(Email::addSignature); addHeader addSignature andThen Email {message="Java 8 FTW!"} Email{message='Dear Sir/Madam: Java 8 FTW! Kind regards'} composing functions
  • 22. Example: A Conversion Function double convert(double amount, double factor, double base) { return amount * factor + base; } // Usage double result = convert(10, 1.8, 32); assertEquals(result, 50, 0.0);
  • 23. Using the conversion function // Temperatures double cInF = convert(10, 1.8, 32); double higherTemp = convert(30, 1.8, 32); // Currencies double dollarsInPounds = convert(10, 0.6, 0); // Distance double kilometresInMiles = convert(27, 0.62137, 0);
  • 24. So what’s the problem? ● Abstraction ○ How do you write something that operates on different conversion functions? ● Reuse ○ How do you use the conversion function in different places?
  • 25.
  • 26. Currying the conversion function double convert(double amount, double factor, double base) { return amount * factor + base; } DoubleUnaryOperator convert(double factor, double base) { return amount -> amount * factor + base; }
  • 27. Using the conversion function DoubleUnaryOperator convert(double factor, double base) { return amount -> amount * factor + base; } DoubleUnaryOperator convertCtoF = convert(1.8, 32); double result = convertCtoF.applyAsDouble(10); assertEquals(result, 50, 0.0);
  • 28.
  • 29. Partial Application Examples // Temperatures DoubleUnaryOperator convertCtoF = convert(1.8, 32); // Currencies DoubleUnaryOperator convert$to£ = convert(0.6, 0); // Distance DoubleUnaryOperator convertKmToMi = convert(0.62137, 0);
  • 30. Definition // int -> (int -> int) IntFunction<IntUnaryOperator> curry(IntBinaryOperator biFunction) { return f -> (s -> biFunction.applyAsInt(f, s)); }
  • 31. Usage IntFunction<IntUnaryOperator> add = curry((f, s) -> f + s); int result = add.apply(1) .applyAsInt(2); assertEquals(3, result);
  • 32. Example currying use cases ● Large factory methods ○ Partially apply some of the arguments and then pass this factory object around. ● Combinators libraries ○ Parsers ○ HTML templating
  • 33. Summary ● Currying is about splitting up the arguments of a function. ● Partial Application is a function “eating” some of its arguments and returning a new function
  • 35. Mutable objects public class TrainJourney { private int price; private TrainJourney onward; public TrainJourney(int price, TrainJourney onward) { this.price = price; this.onward = onward; } public int getPrice() { return price; } public TrainJourney getOnward() { return onward; } public void setPrice(int price) { this.price = price; } public void setOnward(TrainJourney onward) { this.onward = onward; } }
  • 36. Immutable objects public final class TrainJourneyImmutable { private final int price; private final TrainJourneyImmutable onward; public TrainJourneyImmutable(int price, TrainJourney onward) { this.price = price; this.onward = onward; } public int getPrice() { return price; } public TrainJourneyImmutable getOnward() { return onward; } public TrainJourneyImmutable withPrice(int price) { return new TrainJourneyImmutable(price, getOnward()); } public TrainJourneyImmutable withOnward(TrainJourneyImmutable onward) { return new TrainJourneyImmutable(getPrice(), onward); } }
  • 37. Scenario: be able to link together train journeys to form longer journeys.
  • 38.
  • 39. Mutable approach public TrainJourney link(TrainJourney start, TrainJourney continuation) { if (start == null) { return continuation; } TrainJourney t = start; while (t.getOnward() != null) { t = t.getOnward(); } t.setOnward(continuation); return start; } find the last stop in the first journey modify it to link to the continuation journey return the continuation journey if there is no start journey
  • 40. Mutable approach: problem TrainJourney firstJourney = link(start, continuation); TrainJourney secondJourney = link(start, continuation); visit(secondJourney, tj -> { System.out.print(tj.price + " - "); }); static void visit(TrainJourney journey, Consumer<TrainJourney> c) { if (journey != null) { c.accept(journey); visit(journey.onward, c); } }
  • 42.
  • 43. Immutable approach public TrainJourneyImmutable link(TrainJourneyImmutable start, TrainJourneyImmutable continuation) { return start == null ? continuation : new TrainJourneyImmutable(start.getPrice(), link(start.getOnward(), continuation)); }
  • 44. Related topics ● Domain Driven Design ○ Value Classes are Immutable ● Core Java Improvements ○ New date & time library in Java 8 has many Immutable Objects ○ Current Value Types proposal is immutable ● Tooling ○ final keyword only bans reassignment ○ JSR 308 - improved annotation opportunities ○ Mutability Detector ○ Findbugs
  • 45. Downsides to Immutability ● Increased memory allocation pressure ● Some problems harder to model with immutability ○ Deep object graphs ○ Example: Car simulation ● Library interactions ○ ORMs especially ○ Serialisation usually ok these days ● Alternative: small blobs of simple and localised state
  • 46. Immutable objects reduce the scope for bugs.
  • 48. Don’t we all love it? Exception in thread "main" java.lang.NullPointerException
  • 49. public String getCarInsuranceName(Person person) { return person.getCar().getInsurance().getName(); } Where’s the NPE?
  • 50. Defensive checking public String getCarInsuranceName(Person person) { if (person != null) { Car car = person.getCar(); if (car != null) { Insurance insurance = car.getInsurance(); if (insurance != null) { return insurance.getName(); } } } return "No Insurance"; }
  • 51. Optional ● Java 8 introduces a new class java.util.Optional<T> ○ a single-value container ● Explicit modelling ○ Immediately clear that its an optional value ○ better maintainability ● You need to actively unwrap an Optional ○ force users to think about the absence case ○ fewer errors
  • 52. Updating model public class Person { private Optional<Car> car; public Optional<Car> getCar() { return car; } } public class Car { private Optional<Insurance> insurance; public Optional<Insurance> getInsurance() { return insurance; } } public class Insurance { private String name; public String getName() { return name; } }
  • 54. Why it doesn’t work? Optional<People> optPerson = Optional.ofNullable(person); Optional<String> name = optPeople.map(Person::getCar) .map(Car::getInsurance) .map(Insurance::getName); returns Optional<Optional<Car>> Invalid, the inner Optional object doesn’t support the method getInsurance! public class Person { private Optional<Car> car; public Optional<Car> getCar() { return car; } }
  • 55.
  • 57. Chaining methods with flatMap public String getCarInsuranceName(Person person) { return Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); } default value if the resulting Optional is empty
  • 58. A comment on naming public String getCarInsuranceName(Person person) { Set<Person> personSet = person == null ? emptySet() : singleton(person); return personSet.stream() .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unknown"); }
  • 59. Optional in Fields ● Should it be used for fields, or just public methods? ● Pros ○ Explicit modelling ○ Null-safe access ○ Simple getters ● Cons ○ More indirection and GC overhead in Java 8 ○ Not every library understands Optional yet ○ Some libraries require Serializable fields
  • 60. Consistent use of Optional replaces the use of null
  • 62. Summary of benefits ● First-class functions let you cope for requirement changes ● Currying lets you split the parameters of a function to re-use code logic ● Immutability reduces the scope for bugs ● Optional data types lets you reduce null checking boilerplate and prevent bugs
  • 63.
  • 66. Generalised curry function // F -> (S -> R) <F, S, R> Function<F, Function<S, R>> curry(BiFunction<F, S, R> biFunction) { return f -> s -> biFunction.apply(f, s); }