Design Patterns using Lambdas in Java

Sreeram Ajay
14 min readApr 4, 2017

--

We often want to make use of patterns very quickly, if we really think about it, how do we really figure out what pattern to actually use for a given problem statement?
A short anecdote makes it easier to understand, we all agree that grandma makes the best Kheer, right?
You have been telling stories about grandma’s kheer to all your friends, your friends would say well if grandma’s kheer is so good, why don’t you make it?
So you call up your grandma and say ‘Hey granny I have been boasting about your kheer all along, I want a reciepe so that I can make it for my friends.
so she gives you a receipe for the kheer and you write it down very carefully, as you are writing she says, add two spoons of sugar, you would say wait, is it a table spoon or a tea spoon? you ask for all the minute details and once it is done, you would repeat it just to be sure and inquire about the best practices, then you go ahead and start preparing kheer and how did it turn out?
A disaster!! wasn’t it? Last time when I tried this I had lost the spoon with it 😂
Now the point is, it didn’t work.
You finally met you grandma and tell her what a disaster it was. She then consoles you and offers to prepare kheer together and now you are watching her make kheer. Here comes the interesting part, she has to add sugar
and what do you think she does? take two spoons of sugar measure it accurately and put it, right? Alas! no!!
While telling you some stories, she takes some sugar with hand and tosses it in playfully. You would say, wait,what was that? Sugar,
how much did you put? That would suffice, she replies. Shockingly, that’s when you realize grandma never follows the reciepe she has given you.
Similarly, the guys who has written the books on design patterns are the “Grandmas of the Industry” and the worst thing they have done to us is writing the damn books. Now everybody thinks we can actually do it, it is all in the book. No, buddy, no!!
It actually takes years of experience and making mistakes to learn the usage of patterns.

Sequential flow of people (objects)

When coming to usage of patterns, I would prefer to use it as a way to communication rather than a design tool. I f we are to use a pattern, let’s start off by using lighter weight pattern than creating a monster set of patterns. I wanna talk about how patterns would change if we are using them with lambda expressions, well lambda expressions have changed the java remarkably, they give us light weight design tool. let’s see how this really works with a small example.

We all must have used external iterator at some point of time, Suppose we are to print numbers in a list, the very first thing that gets into our mind is “For loop.”

for(int i=0;i<numbers.size();i++)
System.out.println(numbers.get(i));
or
for(int e:numbers)
System.out.println(e);

both of them works perfectly well, but what if we want to minimize code size further, well, we can do it using internal iterator

numbers.forEach(e->System.out.println(e))

yes, now this looks pretty good, but we can still minimize the code further

numbers.forEach(System.out::println)

Woah !! quite impressive , isn’t it? just one line of code!!!

yes,internal iterators looks so simple because, here we focus on what to do to the element rather than how to iterate it.

Strategy

Now let us have a look at how to have Strategy patterns using lambdas.

Assume it is Friday evening and you have plans to go out with your girl friend,
when you are about to leave the office, your boss shows up and stops you, pretty routine as such.
This time he asks you to implement a method to get sum of integers in a list.
Well it is simple, so you would jump in and start coding:

import java.util.*;
public static int totalValues(List<Integer> numbers) {
int total = 0;

for(int number : numbers) {
total += number;
}

return total;
}
public class Simple{
public static void main(String args[]){
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
System.out.println(totalValues(numbers));

}
}
o/p: 21

Code looks good and now you are happy because you can go out, but your boss appears from no where and asks you to write a method which does sum of all even numbers in list.
As most of the code is already written you would start using world’s the most wonderful innovation ‘the Copy & Paste’!!!

public static int totalEvenValues(List<Integer> numbers) {
int total = 0;

for(int number : numbers) {
if(number % 2 == 0) total += number;
}

return total;
}

Your boss says “this looks fine, now I want the sum of all odd numbers in list. ”, but it is already too late and your girl friend will be waiting for you,so you will again use the super power “copy & paste” and then modify the code accordingly.

public static int totalOddValues(List<Integer> numbers) {
int total = 0;

for(int number : numbers) {
if(number % 2 != 0) total += number;
}

return total;
}

If we observe carefully,the above three methods are almost similar except for a half line of code. For this simple change you have implemented 3 methods. You feel like you have made mess out of it, right?
To solve this problem Java8 came out with a new class `Predicate`. Let us see how Predicate will change the way of implementing above functionalities.

public static int totalValues(List<Integer> numbers,
Predicate<Integer> selector) {
int total=0;

for(int number:numbers){
if(selector.test(number)){
total+=number;
}
}
return result;
}

If we compare above implementation with our previous implementation of summing all elements in list, this has little bit of extra code,
if we see into `totalValues` method, we are having 2 parameters
1. List
2. Predicate object
this second parameter carries the condition with it into the method, so that we can check if values in list satisfies that condition.

now let us use Streams, and see how it will change the code readability

public static int totalValues(List<Integer> numbers,
Predicate<Integer> selector) {
return numbers.stream()
.filter(selector)
.mapToInt(value -> value)
.sum();
}

well, how to call this method:

public class Simple{
public static void main(String args[]){
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
System.out.println(totalValues(numbers, number -> true));

}
}
o/p: 21

Now if we want to get sum of even values in list?

we don’t have to change anything in the method, we just need to change the condition while calling that method.

System.out.println(totalValues(numbers, number -> number%2==0));

This looks cool!!! You might ask what if the condition we want to test is complex or with multiple lines, say get sum of prime numbers in list, we say

public class Simple{
public static void main(String args[]){
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
System.out.println(totalValues(numbers, Simple::isPrime));

}
public static boolean isPrime(int number) {
return number > 1 &&
IntStream.range(2, number - 1)
.noneMatch(index -> number % index == 0);
}
}

Here instead of using lambda, we pass our custom defined function name as an argument to ‘totalValues’.

Haha, this time you can say your boss to write what ever condition he wants to 😉

Decorator: Dynamic responsibilities to objects

Let us look at one more interesting pattern say Decorator pattern.

We normally don’t like to use decorator patterns as it looks like:

new BufferedInputStream(new DataInputStream(new ...));

this looks pretty heavy weighted, needs a lot of work and lot of objects being created and we kind of loose interest in the mid way. Before discussing about decorator patterns let us discuss about Function for a minute.

Function<Integer,Integer> inc = e -> e+1;

this `inc` is a lambda function that simply increments the given value, let us use this increment function, for that we have to implement a method say ‘doWork’.

public class Simple{
public static void doWork(int value,
Function<Integer,Integer> func){
System.out.println(func.apply(value));
}
public static void main(String args[]){
Function<Integer,Integer> inc = e -> e+1;
doWork(6,inc);
}
}
o/p: 7

now if we wanna double the value, we can simply call doWork like this:

Function<Integer,Integer> doubleIt= e -> e*2;
doWork(6,doubleIt);

You might ask what if we wanna increment and double it, is it possible to make use of this?
Absolutely yes, we might do something like this:

int temp=inc.apply(6);
System.out.println(doubleIt.apply(temp));

here we have a garbage variable, with the name temp, it says that it is a temporary variable, which is not really needed. so how do we eliminate it?

Function<Integer,Integer> inc = e -> e+1;
Function<Integer,Integer> doubleIt= e -> e*2;
doWork(6,inc.andThen(doubleIt));

In this way we can do a nice chaining of objects very easily. Now we can use this features very effectively. let’s take a look at a very nice example of what we can do to maximize the benefit of these kind of operations. To illustrate that let us create a class ‘Camera’.

java.awt.*;
class Camera{
public Color snap(Color input){

}
}
public class Main{
public static void printSnap(Camera camera){
System.out.println(camera.snap(new Color(120,120,120)));
}
public static void main(String args[]){
printSnap(new Camera());
}
}
o/p:
java.awt.Color[r=120,g=120,b=120]

in the above code we are not doing anything much, just creating an object and printing it. Now let us modify the class Camera further:

class Camera{ 
private Function<Color,Color> filter;
public Camera(){
setFilters();
}
public void setFilters(Function<Color,Color>... filters){
filter = color -> color;
}
public Color snap(Color input){
return filter.apply(input);
}
}

here we have just created a method setFilters that has var arg filters. But for now to begin with we have a filter that does nothing but returning everything it gets unchanged, and we also have implemented snap method that returns input parameter by applying filter that is indicated.

Now let us update the constructor as it is calling setFilters method, it might need parameters to send to setFilters

class Camera{ 
private Function<Color,Color> filter;
public Camera(Function<Color,Color>... filters){
setFilters(Function<Color,Color>... filters);
}
public void setFilters(Function<Color,Color>... filters){
filter = color -> color;
}
public Color snap(Color input){
return filter.apply(input);
}
}

Well, if we see setFilters we have arg parameter, if we have list, we can use list.stream and reduce it to single filter, but now we have array not a filter, so we use Stream.of to reduce array to a single filter.

filter = Stream.of(filters)
.reduce(
color -> color,
(theFilters,aFilter) ->
theFilters.andThen(aFilter)
);

Cool!!! this actually does work well, but let us make it more concise:

filter = Stream.of(filters)
.reduce(
Function.identity(),
Function::andThen
);

Now the camera class looks something like this:

class Camera{ 
private Function<Color,Color> filter;
public Camera(Function<Color,Color>... filters){
setFilters(Function<Color,Color>... filters);
}
public void setFilters(Function<Color,Color>... filters){
filter = Stream.of(filters)
.reduce(
Function.identity(),
Function::andThen);

}
public Color snap(Color input){
return filter.apply(input);
}
}

So now we have our code built up nicely, let’s do something nice… 😊

public class Main{
public static void printSnap(Camera camera){
System.out.println(camera.snap(new Color(120,120,120)));
}
public static void main(String args[]){
printSnap(new Camera());
printSnap(new Camera(Color::brighter));
}
}
o/p:
java.awt.Color[r=120,g=120,b=120]
java.awt.Color[r=171,g=171,b=171]

As you can see in second case , it is actually 171 not 120, so we had applied a little transformation here. We can now do multiple operations quickly and conveniently with a small change:

printSnap(new Camera(Color::brighter,Color:darker));

So we can see how we are bringing in multiple things together. If you notice this is very concise as well, now we can see how easily we can implement a decorator without any chaos or clutter and the noise that we formerly used to.

Cascade: pass (something) on to a succession of others.

Before starting off with the next pattern, let us see a slightly different example and work through it and then draw a pattern. Let us create a class and call it Mailer:

class Mailer {
private void print(String val) { System.out.println(val); }
public void from(String addr) { print("from"); }
public void to(String addr) { print("to"); }
public void subject(String subjectLine) { print("subject"); }
public void body(String message) { print("body"); }
public void send() { print("sending..."); }
}

public class Sample {
public static void main(String[] args) {
Mailer mailer = new Mailer();
mailer.from("ajay@sample.com");
mailer.to("sreeram@sample.com");
mailer.subject("sample subject");
mailer.body("...");
mailer.send();
}
}

this code is a kind of configuration to the mail that we wanna send out.
Have you written code like this before?
This is called java programming, we all might have done this. If we look at this code keenly we have at least two concerns.

  1. look at the noise in this code, see how many times mailer is there(not a good sign)
  2. can I reuse the mailer or not? the point is how do you know?

what if you reuse when you are not supposed to: it will be a bug
what if you wouldn’t reuse when you are supposed to: that’s called inefficiency

wouldn’t it be nice if there is one way of using this, and another way of not using this?
Let us go with the first concern. To solve this, we are going to use cascade method pattern:

class Mailer {
private Mailer print(String val) {
System.out.println(val); return this;
}
public Mailer from(String addr) {
print("from"); return this;
}
public Mailer to(String addr) {
print("to"); return this;
}
public Mailer subject(String subjectLine) {
print("subject"); return this;
}
public Mailer body(String message) {
print("body"); return this;
}
public void send() {
print("sending...");
}
}
public class Sample {
public static void main(String[] args) {
Mailer mailer = new Mailer()
.from("ajay@sample.com")
.to("sreeram@sample.com")
.subject("sample subject")
.body("...")
.send();
}
}

Here we can see how we have effectively removed the noise, some times we call this as “builder pattern”, that’s perfectly nice as well. so you can see how this is going to cascade through.

well,we have still second concern to deal with 🙁
To fix this, let us make few changes in the code, make the method send as static, and modify it a little.

public static void send(Consumer<Mailer> block) { 
Mailer mailer=new Mailer();
block.accept(mailer);
System.out.println("sending...");
}

Consumer is in java.util.function package
Let us see how to use this method in main method

class Mailer {
private Mailer print(String val) {
System.out.println(val); return this;
}
public Mailer from(String addr) {
print("from"); return this;
}
public Mailer to(String addr) {
print("to"); return this;
}
public Mailer subject(String subjectLine) {
print("subject"); return this;
}
public Mailer body(String message) {
print("body"); return this;
}
public static void send(Consumer<Mailer> block) {
Mailer mailer=new Mailer();
block.accept(mailer);
System.out.println("sending...");
}

}
public class Sample {
public static void main(String[] args) {
Mailer.send(mailer -> mailer
.from("ajay@sample.com")
.to("sreeram@sample.com")
.subject("sample subject")
.body("...")
);

}
}

Have you noticed the difference here, usually we pass the object to the function, now we are passing function to a function, but the function intern calls our function that returns the data. We can see the Two way communication.

Now the question is, can I use the mailer object in main method, and the answer is ‘what mailer object are you talking about’ right, because there is no mailer object in our hands because the context of mailer object is within lambda.

Loan

Let us discuss about an interesting example for a while, say we create a class Resource

class Resource{
public Resource(){
System.out.println("resource created")
}
public void op1() {
System.out.println("op1 called....");
}
public void op2() {
System.out.println("op2 called...");
}
public void finalize() {
System.out.println("cleaned....");
}
}
public class Sample{
public static void main(String args[]){
Resource resource=new Resource();
resource.op1();
resource.op2();
}
}
o/p:
resource created
op1 called....
op2 called...

If we observe the output, resource has been created successfully, but it did not clean up. This is because resource will be cleaned up when the memory is cleaned up but that is not a good idea. so let us try to control this behavior by changing finalize to close.

class Resource{
public Resource(){
System.out.println("resource created")
}
public void op1() { System.out.println("op1 called...."); }
public void op2() { System.out.println("op2 called..."); }
public void close() { System.out.println("cleaned...."); }
}
public class Sample{
public static void main(String args[]){
Resource resource=new Resource();
resource.op1();
resource.op2();
resource.close();
}
}

Well, there are two problems in this code:

  1. easy to forget close
  2. exception: what if there is exception and close did not got executed!?

now let us try to rectify problem of ’exception’

public class Sample{
public static void main(String args[]){
try{
Resource resource=new Resource();
resource.op1();
resource.op2();
}finally{
resource.close();
}
}
}
o/p:
resource created
op1 called....
op2 called...
cleaned...

Now again we have two problems:

  1. it is verbose, more stuff you have to write
  2. it is not easy to forget, but easy to forget ++ now (it is not only easy to forget close but also easy to forget try and finally)

Let us fix the second problem, can we reduce verbosity? yes, Java7 has feature called ARM (Automatic Resource Management). we can reduce finally,and lets use try with Resource:

import java.awt.*;
import java.util.stream.*;
import java.util.function.*;
class Resource implements AutoCloseable{
public Resource(){
System.out.println("resource created")
}
public void op1() { System.out.println("op1 called...."); }
public void op2() { System.out.println("op2 called..."); }
public void close() { System.out.println("cleaned...."); }
}
public class Sample{
public static void main(String args[]){
try(Resource resource=new Resource()){
resource.op1();
resource.op2();
}finally{
resource.close();
}
}
}
o/p:
resource created
op1 called....
op2 called...
cleaned...

now java says , you kept AutoClosable there, I will take care of this for you.
now we have removed verbosity, but what about forget fullness?
It’s quite possible to forget try. If we forget, compiler will not give any error or warning.

First thing we have to do is, change the `close` to private method, what do you expect will happen now?
A developer comes along and runs the code, it says you cannot compile it you cannot call close!!

Next thing we have to do is, make Resource constructor as private.
Now the developer is gonna comeback and say what’s this, I cannot create object for this class how do I use this?
We would say, ‘welcome to right way of using this object’.
Let us write a static function ‘use’ in the Resource class.

class Resource{
private Resource(){
System.out.println("resource created")
}
public Resource op1() { System.out.println("op1 called....");return this; }
public Resource op2() { System.out.println("op2 called..."); return this;}
private void close() { System.out.println("finalize called...."); }
public static void use(Consumer<Resource> block){
Resource resource=new Resource();
try{
block.accept(resource);
}finally{
resource.close();
}
}
}

Well as an author of the class I know why to do this, and how to do this. How to call this in main class:

public class Sample implements AutoCloseable{
public static void main(String args[]){
Resource.use(Resource->
resource.op1()
.op2();
}
}
}
o/p:
resource created
op1 called....
op2 called...
cleaned..

Right before the method you wanna do a pre-operation and after the method you wanna do a post-operation. Some times this is also known as loan pattern, because the object is a kind of loan to you.
It doesn’t matter what you do with the object but they do something before you give it for a loan and after you return it. Kind of rental car companies, when we go to good car rental company, they clean the car and give it to you, and when we return the car generally they check for damages, don’t they?

This can be very much useful in projects where there are policies that we have to maintain in code, that can be nicely put in use like method ,
which can enforce those policies and yet give you control, say ‘go do what ever you want to do’ this is very powerful way of writing the code.

This is just a brief idea of how we can actually, effectively use lambda expressions to rethink about design patterns.
Now design patterns have become lot more light weighted. There are few patterns in java, those which are used have become less painful to use, those patterns that we didn’t use in java are now began to come out of the invisibility cloak and become popular.

Thanks to Naga Bhavani Akella for helping me in editing 😊

-Inspired from Venkat Subramanyam (complete content from his talk)

--

--