Over a million developers have joined DZone.

A Refactoring Exercise Using Java8 Lambda Expressions

DZone's Guide to

A Refactoring Exercise Using Java8 Lambda Expressions

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

Finally Java with its 8th major release will get lambda expressions and then will become a bit more functional. Together with Raoul-Gabriel Urma and Alan Mycroft I started writing a book on this topic. Anyway just using lambda expression is probably not enough to claim that you are doing functional programming and, more important, to leverage its potentialities. Now Java supports a new programming paradigm and then people who, like me, did imperative object oriented programming in Java for a dozen years are required to do a quite big mind shift to effectively use these new techniques. For instance, in a former article, I suggested that it's time to stop using the null reference, or at least start using it more sparingly, and replace it with a safer and more explicit construct like an Option.  

In my opinion, a good way to learn how to put lambda expressions at work in a more idiomatic way is to read articles written using other functional languages, better if Scala since it is the most similar to Java, and try to reimplement in Java 8 the patterns and solutions suggested there. This is what I did with the present post that is just a Java translation of a Scala article written by Debasish Ghosh.

The author of that article tried to solve the following, apparently trivial, problem: calculate the net salary of an employee starting from his basic one and applying in sequence the following 4 methods that adds bonuses and subtract taxes to it.

public class SalaryCalculator {
  // B = basic + 20%
  public double plusAllowance(double d) {
  return d * 1.2;

  // C = B + 10%
  public double plusBonus(double d) {
  return d * 1.1;

  // D = C - 30%
  public double plusTax(double d) {
  return d * 0.7;

  // E = D - 10%
  public double plusSurcharge(double d) {
  return d * 0.9;

To make the problem a bit more interesting, Debasish also supposed that the application of all those 4 bonuses or taxes was, one by one, optional. With this last condition a simple, but imperative way, to calculate the net salary could be the following:

public double calculate(double basic, boolean... bs) {
  double salary = basic;
  if (bs[0]) salary = plusAllowance(salary);
  if (bs[1]) salary = plusBonus(salary);
  if (bs[2]) salary = plusTax(salary);
  if (bs[3]) salary = plusSurcharge(salary);
  return salary;

Here bs is an array of 4 booleans (for conciseness I omitted the check on the array length) where each boolean states if the corresponding method should be applied or not. So for example:

calculate(1000.0, true, false, false, true);

calculates the net salary starting from a basic one of 1000 and applying only the allowance (1st method) and the surcharge (4th). So far so good, but as I said, the provided solution is too imperative to satisfy our new functional tastes. As first thing, in order to rewrite it in a more functional style, possibly getting rid of the mutable variable salary and the 4 conditional branches, let's notice that all the 4 methods used to calculate the net salary are in reality a special type of function, called endomorphism, where the only input parameter and the returned value are of the same type. In Java terms an endomorphism can be simply defined as:

interface Endomorphism<A> extends Function<A, A> { }

Actually in the standard Java 8 API it already exists an interface called UnaryOperator defined exactly in the same way. I renamed it Endomorphism here because I think this name is more correct. However, if you prefer, you can just replace my Endomorphism interface with the standard UnaryOperator one in the rest of the article and everything else will work exactly in the same way. To pursue our goal we will also need a second abstraction, a Monoid:

interface Monoid<A> {
  A append(A a1, A a2);
  A zero();

In category theory a monoid is defined as a semigroup with identity. On planet Earth it is just an associative operation on a type that also has a zero. It is now possible to combine these two abstractions and define a Monoid on the Endomorphism type as it follows:

interface EndoMonoid<A> extends Monoid<Endomorphism<A>> {
  default Endomorphism<A> append(Endomorphism<A> a1, Endomorphism<A> a2) {
  return (A a) -> a2.apply(a1.apply(a));

  default Endomorphism<A> zero() {
  return a -> a;

Here the associative operation is the composition of the two functions (I didn't reuse directly the compose() method defined on the Function interface that Endomorphism extends only because it returns a Function instead of an Endomorphism) and the zero is simply the identity function. This is in fact the zero of our Monoid because the composition of any Endomorphism with it returns the Endomorphism itself. Note that I defined another interface instead of class because, using the keyword default, Java 8 allows to add behavior, i.e. implemented methods, to an interface provided that they have no state. In the end we can implement this last interface with an actual class which only purpose is to encapsulate an Endomorphism and provide some convenient methods that will allow us to calculate the net salary with a fluent, and of course functional style.

public class FluentEndoMonoid<A> implements EndoMonoid<A> {
  private final Endomorphism<A> endo;

  public FluentEndoMonoid(Endomorphism<A> endo) {
  this.endo = endo;
  public FluentEndoMonoid(Endomorphism<A> endo, boolean b) {
  this.endo = b ? endo : zero();

  public FluentEndoMonoid<A> add(Endomorphism<A> other) {
  return new FluentEndoMonoid<A>(append(endo, other));
  public FluentEndoMonoid<A> add(Endomorphism<A> other, boolean b) {
  return add(b ? other : zero());

  public Endomorphism<A> get() {
  return endo;

  public static <A> FluentEndoMonoid<A> endo(Endomorphism<A> f, boolean b) {
  return new FluentEndoMonoid<A>(f, b);

In particular the add() method accepting both an Endomorphism and a boolean combines the current Endomorphism with the provided one if the boolean is true or with the zero (the identity function) otherwise. We are now ready to write a functional version of the former calculate method:

public double calculate(double basic, boolean... bs) {
  return endo((Endomorphism<Double>) this::plusAllowance, bs[0])
  .add(this::plusBonus, bs[1])
  .add(this::plusTax, bs[2])
  .add(this::plusSurcharge, bs[3])

As anticipated, the main advantages of this second solution are the absence of both any mutable state and any alternative branch of evaluation. Nevertheless there is a further positive effect of this functional driven refactor that deserves to be underlined: removing the last apply() invocation from the former fluent invocation chain you can obtain a method returning a function for each of the possible 16 combinations of the 4 boolean values in the array. In this way, if for example you have to calculate many salaries for which only the allowance and the surcharge have to be applied you could obtain a function passing to that method a [true, false, false, true] array and then calculate all those salaries just by invoking multiple time apply() on the returned function with the different basic salaries.

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}