Functional Programming in Java - RichardDanielOliva/java-learning-wiki GitHub Wiki
Introduction
The most important features of Java SE 8 are the addition of Lambda Expressions and the Stream API. With the addition of lambda expressions we can create more concise and meaningful code, as well as open the door to functional programming in Java, where functions play a fundamental role.
On the other hand, the API Stream allows us to perform filter/mapping/reduction type operations on data collections sequentially or in parallel and make their implementation transparent to the developer. **Lambdas and Stream **are a very powerful combination that requires a paradigm shift in the way we have written Java code so far.
Declarative vs. imperative programming
Functional programming is a declarative style of programming as opposed to things like object or in a programming and procedural programming which are imperative styles of programming. What this means is that functional programming puts more focus on what things are as opposed to how to get them. Let's expand on this a bit and look at a more programming related example. Let's say that we want to write a program that tells us the average of an array of numbers. Imperative programming would specify the steps required to calculate the result. Something like this.
- Set x equal to zero.
- Add the first number in the array to x
- Repeat step two for the rest of the numbers in the array
- Divide x by the length of the array.
On the other hand, if we wanted to solve the same problem in a declarative way, we could simply say that x is the sum of all the numbers in the array divided by the length of the array.
There are three main concepts behind functional programming which allow us to do just that. These concepts are: one, immutability, two, separating functions and data and three, first-class functions.
Immutability
In functional programming, if we say that x is equal to five, we mean that, for the rest of the program, x will only ever be five. There's no way we can change it. In short, immutability means that most of the values in a program are constant.
In object-oriented and procedural programming, we treat variables as buckets that we can put values into. We call this assigning values to variables. So, at one point in time, x might hold the value three. At another time, it might hold the value 10. At another point, it might be negative four, and so on. On the other hand, in functional programming, we don't assign, we define. Instead of naming buckets that hold different values at different times, we name the values themselves. When we say that x equals three, we don't mean that x is a container that's currently holding the value three, we literally mean that x is three, in the same way that pi is 3.14159 etc. Functional programming treats all values as if they were as concrete and unchanging as pi or any other mathematical constant. And so, once we've defined x, for the whole entire program, x can never be anything else.
The advantage of immutability, and the reason that functional programming places such an emphasis on it, is that it frees us from having to deal with state change. When a program contains many variables that are all changing constantly at different times, it can be very hard to know what state a program is in at any given point in time. As programs increase in size to include thousands or even millions of individual variables, this can lead to extremely hard-to-find bugs and an overall fragile code base that programmers are afraid to make changes to. This is a problem that even test-driven development can't solve completely, since the task of testing all possible states that a program might get itself into is nearly impossible in programs of considerable size. In functional programming, on the other hand, we start off with an immutable set of data as a single source of truth, and then we use functions to combine this data piece by piece and transform it into useful information. This data is usually retrieved from a database or some other memory storage.
There are two powerful advantages to this approach. The first is that the original data in a program will always remain intact, which makes bugs much easier to find. The second is that programs constructed in this way are much easier to keep track of, since you can focus on any given piece individually. The only thing that determines the output of a given piece is the input. We don't have to think about the entire system all the time
Separating functions and data
This is a case where functional programming is directly in contrast with object-oriented programming, where data and functions are almost always grouped together. First of all for our purposes, let's discuss what data and functions actually are.
For our purposes, data might be any values that a program contains, people's names, addresses, and social security numbers in a payroll program, the models, years, and colors of cars on a used car website, the positions, health levels and weapons of characters in a video game, anything. All of this is data. In object-oriented programming, this data is usually wrapped up inside objects as member variables, and the only way we can access it is using an object's methods. In functional programming on the other hand, this data is represented by simple arrays and hashes.
Function is any operation that we can apply to our data to convert it into useful information. For example, if we want to find the average salary of programmers at our company, find all the cars on our website that were made after a certain year, or find if two characters are colliding in our video game. In object-oriented programming, functions are wrapped up inside objects along with the data that they operate on, and allow us to access or make changes to that data. In functional programming on the other hand, functions are completely separate entities from the data that they operate on. In order to operate on given data, the data must be passed as arguments to the function and because of the rule of immutability, they should never make changes to any of the data they touch. They only return a modified copy of that data.
First-class functions
One of the concepts of functional programming is that functions (methods) are defined as first-level entities, that is, that they may appear in parts of the code where other first-level entities, such as primitive values or objects, appear. This means to be able to pass functions, in execution time, as values of variables, return values or parameters of other functions. This is a very powerful concept that can be understood as the possibility of passing behavior as value and it is precisely what we can achieve with the addition of lambda expressions to the Java language.