SlideShare a Scribd company logo
1 of 54
Download to read offline
Pragmatic Functional 
Refactoring with Java 8 
Raoul-Gabriel Urma 
Richard Warburton
First-class Functions 
Currying 
Immutability 
Optional Data Types 
Conclusions
Step 1: filtering invoices from Oracle 
public List<Invoice> filterInvoicesFromOracle(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> filterInvoicesFromCustomer(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> filterInvoicesEndingWith(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> filterInvoicesBad(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 Predicate<T> { 
boolean test(T t); 
} 
Invoice boolean 
Predicate<Invoice>
Step 4b: using different criterion with objects 
private List<Invoice> filterInvoices(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 = 
filterInvoices(invoices, new FacebookTraining()); 
private 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 = 
filterInvoices(invoices, this::isOracleInvoice); 
List<Invoice> trainingInvoices = 
filterInvoices(invoices, this::isTrainingInvoice); 
method references
Step 6: lambdas 
List<Invoice> oracleInvoices = 
filterInvoices(invoices, 
(Invoice invoice) -> invoice.getCustomer() == Customer.ORACLE); 
List<Invoice> trainingInvoices = 
filterInvoices(invoices, 
(Invoice invoice) -> invoice.getName().endsWith(("Training")));
First-class functions 
● Scary functional-programming terminology for a common object-oriented 
pattern (strategy, function object…) 
● All it means is the ability to use a function (method reference, lambda, 
object representing a function) just like a regular value 
○ Pass it as argument to a method 
○ Store it in a variable 
● Lets you cope with requirement changes by representing and passing 
the new requirement as a function
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() 
creating more complex 
functions from building blocks 
.filter( isFacebookInvoice.or(this::isGoogleInvoice)) 
.collect(toList());
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 Letter { 
private final String message; 
public Letter(String message) { 
this.message = message; 
} 
public Letter addDefaultHeader(){ 
return new Letter("From her majesty:n" + message); 
} 
public Letter checkSpelling(){ 
return new Letter(message.replaceAll("FTW", "for the win")); 
} 
public Letter addDefaultFooter(){ 
return new Letter(message + "nKind regards"); 
} 
}
Creating function pipelines (2) 
import java.util.function.Function; 
Function<Letter, Letter> addHeader = Letter::addDefaultHeader; 
Function<Letter, Letter> processingPipeline = 
addHeader.andThen(Letter::checkSpelling) 
.andThen(Letter::addDefaultFooter); 
andThen andThen 
composing 
functions 
addHeader checkSpelling addFooter 
Letter 
{message="Java 
8 FTW!"} 
Letter{message='From 
her majesty: 
Java 8 for the win! 
Kind regards'}
Creating function pipelines (3) 
import java.util.function.Function; 
Function<Letter, Letter> addHeader = Letter::addDefaultHeader; 
Function<Letter, Letter> processingPipeline = 
addHeader.andThen(Letter::addDefaultFooter); 
andThen 
composing 
functions 
addHeader addFooter 
Letter 
{message="Java 
8 FTW!"} 
Letter{message='From 
her majesty: 
Java 8 FTW! 
Kind regards'}
First-class Functions 
Currying 
Immutability 
Optional Data Types 
Conclusions
A conversion function 
// (double, double, double) -> double 
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);
Currying the conversion function 
// (double, double) -> (double -> double) 
DoubleUnaryOperator convert(double factor, double base) { 
return amount -> amount * factor + base; 
} 
// Partial Application 
DoubleUnaryOperator convertCtoF = convert(1.8, 32); 
// Usage 
double result = convertCtoF.applyAsDouble(10); 
assertEquals(result, 50, 0.0);
More partial application 
// Temperatures 
DoubleUnaryOperator convertCtoF = convert(1.8, 32); 
// Currencies 
DoubleUnaryOperator convert$to£ = convert(0.6, 0); 
// Distance 
DoubleUnaryOperator convertKmToMi = convert(0.62137, 0);
A curry function 
// 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);
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); 
}
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 
● You can write your functions in curried form from the beginning or use 
a function to curry them.
First-class Functions 
Currying 
Immutability 
Optional Data Types 
Conclusions
Mutable objects 
public class TrainJourney { 
private int price; 
private TrainJourney onward; 
public TrainJourney(int p, TrainJourney t) { 
price = p; 
onward = t; 
} 
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 class TrainJourneyImmutable { 
private final int price; 
private final TrainJourneyImmutable onward; 
public TrainJourneyImmutable(int p, TrainJourneyImmutable t) { 
price = p; 
onward = t; 
} 
public int getPrice() { 
return price; 
} 
public TrainJourneyImmutable getOnward() { 
return onward; 
} 
public TrainJourneyImmutable setPrice(int price) { 
return new TrainJourneyImmutable(price, getOnward()); 
} 
public TrainJourneyImmutable setOnward(TrainJourneyImmutable onward) 
{ 
return new TrainJourneyImmutable(getPrice(), onward); 
} 
}
Mutable approach 
public TrainJourney link(TrainJourney tj1, TrainJourney tj2) { 
if (tj1 == null) { 
return tj2; 
} 
TrainJourney t = tj1; 
while (t.getOnward() != null) { 
t = t.getOnward(); 
} 
t.setOnward(tj2); 
return tj1; 
}
Mutable approach: problem 
TrainJourney linked1 = link(tj1, tj2); 
TrainJourney linked2 = link(tj1, tj2); 
visit(linked2, 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 append(TrainJourneyImmutable tj1, 
TrainJourneyImmutable tj2) { 
return tj1 == null ? tj2 
: new TrainJourneyImmutable(tj1.getPrice(), 
append(tj1.getOnward(), tj2) 
); 
}
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
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; } 
}
Refactoring our example 
public String getCarInsuranceName(Person person) { 
return Optional.ofNullable(person) 
.flatMap(Person::getCar) 
.flatMap(Car::getInsurance) 
.map(Insurance::getName) 
.orElse("No Insurance"); 
}
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 re-use code logic 
● Immutability reduces the scope for bugs 
● Optional data types lets you reduce null checking boilerplate and 
prevent bugs
Training Website: http://java8training.com 
http://manning.com/urma http://tinyurl.com/java8lambdas
Any Questions? 
Richard Warburton 
@richardwarburto 
Raoul-Gabriel Urma 
@raoulUK
Example currying use cases 
● Large factory methods 
○ Partially apply some of the arguments and then pass this factory 
object around. 
● Parser Combinators 
○ many(‘a’) - function which parses a, aa, aaa, etc.

More Related Content

What's hot

If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
Mario Fusco
 

What's hot (20)

Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 
Event handling
Event handlingEvent handling
Event handling
 
Introduction to ParSeq: to make asynchronous java easier
Introduction to ParSeq: to make asynchronous java easierIntroduction to ParSeq: to make asynchronous java easier
Introduction to ParSeq: to make asynchronous java easier
 
Introduction to java 8 stream api
Introduction to java 8 stream apiIntroduction to java 8 stream api
Introduction to java 8 stream api
 
Spring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerSpring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & Micrometer
 
Railway Oriented Programming
Railway Oriented ProgrammingRailway Oriented Programming
Railway Oriented Programming
 
Introduction to GoLang
Introduction to GoLangIntroduction to GoLang
Introduction to GoLang
 
L'API Collector dans tous ses états
L'API Collector dans tous ses étatsL'API Collector dans tous ses états
L'API Collector dans tous ses états
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
Optional in Java 8
Optional in Java 8Optional in Java 8
Optional in Java 8
 
Dependency Breaking Techniques
Dependency Breaking TechniquesDependency Breaking Techniques
Dependency Breaking Techniques
 
Git & Github for beginners
Git & Github for beginnersGit & Github for beginners
Git & Github for beginners
 
Functional Java 8 in everyday life
Functional Java 8 in everyday lifeFunctional Java 8 in everyday life
Functional Java 8 in everyday life
 
Lazy java
Lazy javaLazy java
Lazy java
 
RxJS Operators - Real World Use Cases (FULL VERSION)
RxJS Operators - Real World Use Cases (FULL VERSION)RxJS Operators - Real World Use Cases (FULL VERSION)
RxJS Operators - Real World Use Cases (FULL VERSION)
 
Introduction à JPA (Java Persistence API )
Introduction à JPA  (Java Persistence API )Introduction à JPA  (Java Persistence API )
Introduction à JPA (Java Persistence API )
 
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
Introduction à spring boot
Introduction à spring bootIntroduction à spring boot
Introduction à spring boot
 
Java 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional InterfacesJava 8 Lambda Built-in Functional Interfaces
Java 8 Lambda Built-in Functional Interfaces
 

Viewers also liked

Viewers also liked (6)

Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)Refactoring to Java 8 (Devoxx BE)
Refactoring to Java 8 (Devoxx BE)
 
Java 8 by example!
Java 8 by example!Java 8 by example!
Java 8 by example!
 
Pragmatic functional refactoring with java 8 (1)
Pragmatic functional refactoring with java 8 (1)Pragmatic functional refactoring with java 8 (1)
Pragmatic functional refactoring with java 8 (1)
 
Migrating to IntelliJ IDEA from Eclipse
Migrating to IntelliJ IDEA from EclipseMigrating to IntelliJ IDEA from Eclipse
Migrating to IntelliJ IDEA from Eclipse
 
Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams Productive Programming in Java 8 - with Lambdas and Streams
Productive Programming in Java 8 - with Lambdas and Streams
 
Functional programming with Java 8
Functional programming with Java 8Functional programming with Java 8
Functional programming with Java 8
 

Similar to Pragmatic functional refactoring with java 8

Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
ShriKant Vashishtha
 
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
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class Functions
Eelco Visser
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
Mario Fusco
 

Similar to Pragmatic functional refactoring with java 8 (20)

Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8Pragmatic Functional Refactoring with Java 8
Pragmatic Functional Refactoring with Java 8
 
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...
 
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...
 
Is java8a truefunctionallanguage
Is java8a truefunctionallanguageIs java8a truefunctionallanguage
Is java8a truefunctionallanguage
 
Is java8 a true functional programming language
Is java8 a true functional programming languageIs java8 a true functional programming language
Is java8 a true functional programming language
 
Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)Currying and Partial Function Application (PFA)
Currying and Partial Function Application (PFA)
 
SeneJug java_8_prez_122015
SeneJug java_8_prez_122015SeneJug java_8_prez_122015
SeneJug java_8_prez_122015
 
Functional Programming
Functional ProgrammingFunctional Programming
Functional Programming
 
Array Cont
Array ContArray Cont
Array Cont
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class Functions
 
Java8
Java8Java8
Java8
 
Functional programming 101
Functional programming 101Functional programming 101
Functional programming 101
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In Java
 
Unit 4 (1)
Unit 4 (1)Unit 4 (1)
Unit 4 (1)
 
Functional Programming for OO Programmers (part 2)
Functional Programming for OO Programmers (part 2)Functional Programming for OO Programmers (part 2)
Functional Programming for OO Programmers (part 2)
 
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
 
Higher Order Components and Render Props
Higher Order Components and Render PropsHigher Order Components and Render Props
Higher Order Components and Render Props
 
FP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyondFP in Java - Project Lambda and beyond
FP in Java - Project Lambda and beyond
 

More from RichardWarburton

More from 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
 
Java collections the force awakens
Java collections  the force awakensJava collections  the force awakens
Java collections the force awakens
 
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
 
Jvm profiling under the hood
Jvm profiling under the hoodJvm profiling under the hood
Jvm profiling under the hood
 
How to run a hackday
How to run a hackdayHow to run a hackday
How to run a hackday
 
Generics Past, Present and Future
Generics Past, Present and FutureGenerics Past, Present and Future
Generics Past, Present and Future
 
Performance and predictability (1)
Performance and predictability (1)Performance and predictability (1)
Performance and predictability (1)
 
Performance and predictability
Performance and predictabilityPerformance and predictability
Performance and predictability
 
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
 
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
 

Recently uploaded

Recently uploaded (20)

Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
"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 ...
 
[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf[BuildWithAI] Introduction to Gemini.pdf
[BuildWithAI] Introduction to Gemini.pdf
 
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
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 AmsterdamDEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
DEV meet-up UiPath Document Understanding May 7 2024 Amsterdam
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
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
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
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...
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
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
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
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
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 

Pragmatic functional refactoring with java 8

  • 1. Pragmatic Functional Refactoring with Java 8 Raoul-Gabriel Urma Richard Warburton
  • 2.
  • 3.
  • 4. First-class Functions Currying Immutability Optional Data Types Conclusions
  • 5. Step 1: filtering invoices from Oracle public List<Invoice> filterInvoicesFromOracle(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> filterInvoicesFromCustomer(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> filterInvoicesEndingWith(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> filterInvoicesBad(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 Predicate<T> { boolean test(T t); } Invoice boolean Predicate<Invoice>
  • 10. Step 4b: using different criterion with objects private List<Invoice> filterInvoices(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 = filterInvoices(invoices, new FacebookTraining()); private 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 = filterInvoices(invoices, this::isOracleInvoice); List<Invoice> trainingInvoices = filterInvoices(invoices, this::isTrainingInvoice); method references
  • 13. Step 6: lambdas List<Invoice> oracleInvoices = filterInvoices(invoices, (Invoice invoice) -> invoice.getCustomer() == Customer.ORACLE); List<Invoice> trainingInvoices = filterInvoices(invoices, (Invoice invoice) -> invoice.getName().endsWith(("Training")));
  • 14. First-class functions ● Scary functional-programming terminology for a common object-oriented pattern (strategy, function object…) ● All it means is the ability to use a function (method reference, lambda, object representing a function) just like a regular value ○ Pass it as argument to a method ○ Store it in a variable ● Lets you cope with requirement changes by representing and passing the new requirement as a function
  • 15. Composing functions Functions Composing functions
  • 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() creating more complex functions from building blocks .filter( isFacebookInvoice.or(this::isGoogleInvoice)) .collect(toList());
  • 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 Letter { private final String message; public Letter(String message) { this.message = message; } public Letter addDefaultHeader(){ return new Letter("From her majesty:n" + message); } public Letter checkSpelling(){ return new Letter(message.replaceAll("FTW", "for the win")); } public Letter addDefaultFooter(){ return new Letter(message + "nKind regards"); } }
  • 19. Creating function pipelines (2) import java.util.function.Function; Function<Letter, Letter> addHeader = Letter::addDefaultHeader; Function<Letter, Letter> processingPipeline = addHeader.andThen(Letter::checkSpelling) .andThen(Letter::addDefaultFooter); andThen andThen composing functions addHeader checkSpelling addFooter Letter {message="Java 8 FTW!"} Letter{message='From her majesty: Java 8 for the win! Kind regards'}
  • 20. Creating function pipelines (3) import java.util.function.Function; Function<Letter, Letter> addHeader = Letter::addDefaultHeader; Function<Letter, Letter> processingPipeline = addHeader.andThen(Letter::addDefaultFooter); andThen composing functions addHeader addFooter Letter {message="Java 8 FTW!"} Letter{message='From her majesty: Java 8 FTW! Kind regards'}
  • 21. First-class Functions Currying Immutability Optional Data Types Conclusions
  • 22.
  • 23.
  • 24. A conversion function // (double, double, double) -> double 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);
  • 25. Currying the conversion function // (double, double) -> (double -> double) DoubleUnaryOperator convert(double factor, double base) { return amount -> amount * factor + base; } // Partial Application DoubleUnaryOperator convertCtoF = convert(1.8, 32); // Usage double result = convertCtoF.applyAsDouble(10); assertEquals(result, 50, 0.0);
  • 26. More partial application // Temperatures DoubleUnaryOperator convertCtoF = convert(1.8, 32); // Currencies DoubleUnaryOperator convert$to£ = convert(0.6, 0); // Distance DoubleUnaryOperator convertKmToMi = convert(0.62137, 0);
  • 27. A curry function // 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);
  • 28. 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); }
  • 29. 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 ● You can write your functions in curried form from the beginning or use a function to curry them.
  • 30. First-class Functions Currying Immutability Optional Data Types Conclusions
  • 31. Mutable objects public class TrainJourney { private int price; private TrainJourney onward; public TrainJourney(int p, TrainJourney t) { price = p; onward = t; } 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; } }
  • 32. Immutable objects public class TrainJourneyImmutable { private final int price; private final TrainJourneyImmutable onward; public TrainJourneyImmutable(int p, TrainJourneyImmutable t) { price = p; onward = t; } public int getPrice() { return price; } public TrainJourneyImmutable getOnward() { return onward; } public TrainJourneyImmutable setPrice(int price) { return new TrainJourneyImmutable(price, getOnward()); } public TrainJourneyImmutable setOnward(TrainJourneyImmutable onward) { return new TrainJourneyImmutable(getPrice(), onward); } }
  • 33. Mutable approach public TrainJourney link(TrainJourney tj1, TrainJourney tj2) { if (tj1 == null) { return tj2; } TrainJourney t = tj1; while (t.getOnward() != null) { t = t.getOnward(); } t.setOnward(tj2); return tj1; }
  • 34.
  • 35. Mutable approach: problem TrainJourney linked1 = link(tj1, tj2); TrainJourney linked2 = link(tj1, tj2); visit(linked2, tj -> { System.out.print(tj.price + " - "); }); static void visit(TrainJourney journey, Consumer<TrainJourney> c) { if (journey != null) { c.accept(journey); visit(journey.onward, c); } }
  • 37. Immutable approach public TrainJourneyImmutable append(TrainJourneyImmutable tj1, TrainJourneyImmutable tj2) { return tj1 == null ? tj2 : new TrainJourneyImmutable(tj1.getPrice(), append(tj1.getOnward(), tj2) ); }
  • 38.
  • 39. 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
  • 40. Immutable objects reduce the scope for bugs.
  • 41. First-class Functions Currying Immutability Optional Data Types Conclusions
  • 42. Don’t we all love it? Exception in thread "main" java.lang.NullPointerException
  • 43. public String getCarInsuranceName(Person person) { return person.getCar().getInsurance().getName(); } Where’s the NPE?
  • 44. 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"; }
  • 45. 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
  • 46. 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; } }
  • 47. Refactoring our example public String getCarInsuranceName(Person person) { return Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("No Insurance"); }
  • 48. Consistent use of Optional replaces the use of null
  • 49. First-class Functions Currying Immutability Optional Data Types Conclusions
  • 50. Summary of benefits ● First-class functions let you cope for requirement changes ● Currying lets you re-use code logic ● Immutability reduces the scope for bugs ● Optional data types lets you reduce null checking boilerplate and prevent bugs
  • 51.
  • 52. Training Website: http://java8training.com http://manning.com/urma http://tinyurl.com/java8lambdas
  • 53. Any Questions? Richard Warburton @richardwarburto Raoul-Gabriel Urma @raoulUK
  • 54. Example currying use cases ● Large factory methods ○ Partially apply some of the arguments and then pass this factory object around. ● Parser Combinators ○ many(‘a’) - function which parses a, aa, aaa, etc.