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

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
 

What's hot (20)

Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Clean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a MonolithClean Pragmatic Architecture - Avoiding a Monolith
Clean Pragmatic Architecture - Avoiding a Monolith
 
Kotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime PerformanceKotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime Performance
 
Code Smells and Its type (With Example)
Code Smells and Its type (With Example)Code Smells and Its type (With Example)
Code Smells and Its type (With Example)
 
The Art of Clean code
The Art of Clean codeThe Art of Clean code
The Art of Clean code
 
Models for hierarchical data
Models for hierarchical dataModels for hierarchical data
Models for hierarchical data
 
Asynchronous Programming at Netflix
Asynchronous Programming at NetflixAsynchronous Programming at Netflix
Asynchronous Programming at Netflix
 
The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)The Power of Composition (NDC Oslo 2020)
The Power of Composition (NDC Oslo 2020)
 
Clean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionClean Code: Chapter 3 Function
Clean Code: Chapter 3 Function
 
Idiomatic Kotlin
Idiomatic KotlinIdiomatic Kotlin
Idiomatic Kotlin
 
Clean Code
Clean CodeClean Code
Clean Code
 
Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.Java 8 Stream API. A different way to process collections.
Java 8 Stream API. A different way to process collections.
 
Clean Code
Clean CodeClean Code
Clean Code
 
clean code book summary - uncle bob - English version
clean code book summary - uncle bob - English versionclean code book summary - uncle bob - English version
clean code book summary - uncle bob - English version
 
Optional in Java 8
Optional in Java 8Optional in Java 8
Optional in Java 8
 
Java 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & StreamsJava 8 Lambda Expressions & Streams
Java 8 Lambda Expressions & Streams
 
The Evolution of Scala
The Evolution of ScalaThe Evolution of Scala
The Evolution of Scala
 
Clean code
Clean codeClean code
Clean code
 
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
 
Refactoring and code smells
Refactoring and code smellsRefactoring and code smells
Refactoring and code smells
 

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
 

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
 
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
 

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

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 

Recently uploaded (20)

GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 

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.