Posted on

An Introduction to Functional Programming in Java 8: Part 0 - Motivation

As I’ve seen in my previous post, the interest in functional programming is high. This is the reason I want to write an introduction about it.

I work a lot in Haskell and Java in my free time. The idea to combine both of these languages in Java was a dream come true. After this introduction, I hope you will feel the same.

What is functional programming, really?

You might have heared about functional programming (fP) and how great it is to reduce your LOC and to enhance the readability of your code. But what does it really mean to program functional and what are the main differences to OOP?

1. All variables are final

Lets look at this function to greet some users. First of, it is written OO.
 public String greet(List<String> names) {
    String greeting = "Welcome ";
    for(String name : names) {
        greeting += name + " "; // We don't care about the last space right now.
    }
    greeting += "!";
    return greeting;
}

This is a perfectly valid function to create such a greet String in Java.

But if you you are fP, this won’t work. You change the state of greeting, which is not allowed in fP. So if you try to make greeting final, you would get an error. Every time you use += with that String, you change its state.

What you basically do in fP is the concatination of all names in one line into one String.

public String greet(List<String> names) {
    final String reducedString = "Welcome " + names.get(0) + " " + names.get(1) + " " + ...
            + names.get(names.size()-1) + " ";
    return reducedString + "!";
}

If you think think that this looks nasty, you’re right! But there is a fP function to make this nicer.

I will give you the right fP function here. Don’t worry if you don’t understand it now, we will talk about all of this in part 3

public String greet(List<String> names) {
    String greeting = names
            .stream()
            .map(name -> name + " ")
            .reduce("Welcome ",
                    (acc, name) -> acc + name);
    return greeting + "!";
}

The good think about final variables is that their value is always the same. This makes debugging and testing so much easier!

2. Don’t use global variables (and forget about side effects)

I’ve choosen the example of a global time object. You write a static function, which returns the current time as a String. A OO function could look like this:

public class Utils {

    private static Time time;

    public static String currTime() {
        return time.getTime().toString();
    }

}

If you use currTime twice, the result will be different, because the time will be different. Although we had the same input (which is none), currTime had two different results!

This can’t happen in fP. Every method only depense on its parameters and on nothing else! So if we want to do something like this, the Time object, which should be a set time, has to be a parameter of currTime:

public class Utils {

    public static String currTime(FixedTime time) {
        return fixedTime.now().toString();
    }

}

This might seem odd in the OO world, but it has some benefits.

On one hand, it is much easier to read the code. If you know that a method only relies on its parameter, you don’t have to look for global variables that do the magic in your method. On the other hand, testing is much easier too! When you want to test the fP currTime method, you can mock the Time object. In the OO version, it’s really difficult to mock the static Time object.

3. Use functions as parameters

In fP, functions can be arguments of another function! How cool is that? Just think of a function which adds 1 to every number of a List<Integer>. How would you do that OO? Here’s a snippet:

public List<Integer> addOne(List<Integer> numbers) {
    List<Integer> plusOne = new LinkedList<>();

    for(Integer number : numbers) {
        plusOne.add(number + 1);
    }

    return plusOne;
}

Now you have to handle two lists. This can be very confusing and leads to errors. There is also the chance to change the state of numbers. This could lead to problems in later parts of the program

In fP, you can map a function with every element of a List. In this example this means, that you want to “map” number+1 to every item in the list and store this in a new List.

Don’t worry if you don’t understand all of it now, we will learn about this in part 3. The fP method would look like this:

public List<Integer> addOne(List<Integer> numbers) {
    return numbers
            .stream()
            .map(number -> number + 1)
            .collect(Collectors.toList());
}

This reduces the number of variables and therefore the places where you can make errors. Here, you create a new list and leave numbers like it is.

Conclusion

I hope you can see the benefits of fP. Later on, you will learn to truly appreciate them. Final variables are a big help in terms of multi-threading, the lack of global variables improves the testability and functions as parameters improve the code quality.

And don’t worry, in the beginning you can mix OOP and fP in your code.

In the next part, we will talk about functions as parameters. Therefore, I will introduce anonymous function(lambdas) and method references.

I hope you liked this short introduction in the big topic of functional programming. Please write me when something’s not clear. Or are there any reason for you to hate functional programming at all? I would love to discuss these topics with you.

Want to contact me or leave some feedback? Write an e-mail to me.