SlideShare uma empresa Scribd logo
1 de 66
Baixar para ler offline
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);
}

Mais conteúdo relacionado

Mais procurados

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
 

Mais procurados (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
 

Destaque

Destaque (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)
 

Semelhante 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
 

Semelhante 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
 

Mais de RichardWarburton

Mais 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

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
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Último (20)

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...
 
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)
 
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
 
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
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
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
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 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
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
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
 
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
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
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
 
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...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 

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); }