Introduction to Functional Programming
Victor J. Reventos
What is Functional Programming?
- It’s a style of programming that treats programs as evaluation of mathematical functions and avoids mutable state and side effects
Functional Programming Benefits
- Declarative Code (what vs how)
- Explicitness
- Concurrency
- Composability & Modularity
- Testability
- Easy to understand code
FP Concepts
- Declarative vs Imperative
- Pure Functions
- Higher Order Functions
- Function Composition
- Immutability
- Map/Filter/Reduce
Declarative vs Imperative
- Defining WHAT to do vs HOW to do it
- Expressive
- Eliminate side-effects as much as possible
Declarative vs Imperative
// Imperative
public static List<Integer> evenNumbers(List<Integer> integers) {
final List<Integer> result = new ArrayList<>();
for (Integer i : integers) {
if (i % 2 == 0) {
result.add(i);
}
}
return result;
}
// Declarative / Function
public static List<Integer> evenNumbers(List<Integer> integers) {
return integers.stream()
.filter(i -> i % 2 == 0)
.collect(ImmutableList.toImmutableList());
}Pure Functions
- Pure functions act on their parameters
- Always produce the same output for the given parameters
- Calling the function a "thousand times" should return the same value a every time.
- Have No side effects
Pure Functions
public int value() {
return 10;
}
public int add(int x, int y) {
return x + y
}
public long countCharacters(List<String> strings) {
return strings.stream()
.map(String::length)
.count();
}Impure Functions
public class Impure {
private int counter = 1;
public int value() {
return counter++;
}
public int add(int x, int y) {
return x + y + counter++;
}
}
public String sayHello(Person person) {
// Nasty side effect
person.setGreeted(true);
return "Hello " + person.getName();
}Referential Transparency
- An expression is said to be referentially transparent if it can be replaced with its corresponding value without changing the program's behavior
- A function composed of pure functions is a referentially transparent function
In short, it does what the type signature says its going to do.
Referential Transparency
// referentially transparent
// no surprises
public int multiply(int x, int y) {
return x * y;
}
// Not referentially transparent
// is not valid for y = 0 and it will throw an exception
public int divide(int x, int y) {
return x / y;
}
// Where does it force me to handle an error?
public int doSomething() {
// do work
// sneaky who knew I would give you a nasty side effect
// exceptions: the glorified GOTO statement.
throw new RuntimeException();
}Higher Order Functions
- Functions are first class citizens
- Functions can take functions as arguments
- Functions can return functions
- Enables function composition
Higher Order Functions - Locking
public class Locking {
// properly handle locking and unlock even when exceptions happen.
public <T> T withLock(Lock lock, Supplier<T> supplier) {
lock.lock();
try {
return supplier.get();
} finally {
lock.unlock();
}
}
}
Higher Order Functions - Timing
@Log4j2
public class Timing {
public static <T> T time(Supplier<T> supplier, Consumer<Long> timeConsumer) {
val startTime = System.nanoTime();
val value = supplier.get();
timeConsumer.accept(System.nanoTime() - startTime);
return value;
}
public int doRealWork() {
return 20 * 20;
}
public int timeDoRealWork() {
return time(this::doRealWork, log::info);
}
}Function Composition
Is applying one function to the results of another: The result of f() is sent through g() It is written: (g º f)(x)
newFunction(x) = g(f(x))
Function Composition
public class Composition {
public Function<Integer, Integer> times2() {
return x -> x * 2;
}
public Function<Integer, Integer> square() {
return x -> x * x;
}
public Function<Integer, Integer> squareTimes2() {
return times2().andThen(square());
}
public Function<Integer, Integer> squaredTimes4() {
return times2().andThen(times2()).andThen(square());
}
// see... LEGOS
public Function<Integer, String> squaredTimes2InHex() {
return squareTimes2().andThen(Integer::toHexString);
}
}Immutability
- An immutable object is an object whose state cannot be modified after it is created
- Are thread-safe
- Easy to test
- Easy to track (no need to keep track how/where your object changes)
- Favors caching
Immutability
@Value
@Builder
public ImmutableDataClass {
private final String field1;
private final int field2;
...
}Common Functional Functions
- map - Transforms a value into another
- filter - Returns the value if it matches the given predicate
- reduce - Applies a given function against an accumulator to reduce it to a single value
Problem - Count the number of Album titles that start with "Pop"
public long countTheNumberOfTitlesThatStartWithPop(List<Album> albums) {
return albums.stream()
// transform Album -> String
.map(Album::getTitle)
// filter - keep titles that start with "Pop"
.filter(title -> title.startsWith("Pop"))
// reduce -> accumulate over a count
// this could also be written using .count()
.reduce(0, (accumulator, title) -> accumulator + 1);
}Null
- Null breaks composition
// this is not a referentially transparent function
// where in the type signature does it say that the User might be absent?
public Function<Integer, User> getUser() {
return id -> null;
}
public Function<User, Comments> getUserComments() {
return user -> {
if (user != null) {
// fetch user comments
} else {
return null;
}
};
}
public Function<Integer, Comments> getComments() {
return getUser().andThen(getComments());
}Optional to the Rescue
- Generally known as encoding effects with types
- Optional models the potential absence of a value
// The type signature tells you that user might be absent.
public Optional<User> getUser(int id) {
return Optional.empty();
}
public Comments getUserComments(User user) {
// fetch comments
}
public Result doSomethingWithComments() {
val comments = getUser(1).map(this::getUserComments);
// do something with it.
}

Advanced Topics
- Monoids / Functors / Applicative
- Functional Architecture
- Functional Error Handling
Questions?
May the Function be with you.
Introduction to Functional Programming
By Victor J. Reventos
Introduction to Functional Programming
Introduction to functional programming with Java examples.
- 121