Functional programming in Java
Since the very beginning of Java, it kept its place as an object oriented language and almost mastered it. However, as time passed by, Java community has seen the urgent need to allow other concepts and paradigms to be implemented in java, to keep it flexible enough in the cutthroat competition.
Programming paradigms
Paradigm means a way of thinking of a solution. So, throughout the history of humanity and specifically in the software, there are too many ways of thinking (paradigms) but let's focus on two paradigms here that matter to us
Imperative -> Mainly focusing on "How to solve the problem"
Declarative -> Mainly focusing on "What to solve"
Imperative VS Declarative
Since it's a way of thinking so let's take it out of the software first.
"We want to know the average age of a group of people"
Imperative:
Ask everyone in the group in order about their age
Add their age to a value called "sum"
Increase the "count" number
Once done, divide the sum per count
Declarative:
Get the sum of the age
Divide by the number of the group
Here we can see, the major difference is what is the most important to us in the problem. While in imperative we care about the flow and the steps taken to achieve the result, in declarative we care much more about the problem itself and divide it into smaller problems to be solved.
OOP is an implementation of the imperative, while functional programming is an implementation of the declarative.
Functional programming (FP)
As per its name, we are depending here on the functions, composing functions, using functions and even passing functions as an argument to another function, hence a few rules have been set to assure that we get the maximum advantages of this paradigm which are:
Immutability
Functional purity
First-Class functions
Functional programming rules - Immutability
Mutability is the ability to change throughout the code, we can use setters to change a member of an instance, or simply assign a new value for a variable.
Although the meaning of (=) in OOP is assigning, in FP it means defining. In another word, in OOP if I say: int x = 5;
In OOP -> x is a container that holds the value of (5)
In FP -> x is 5.
That means I can not define (x) as 5, then redefine (x) as 10. We will define a variable as (5) then we'll define another variable as (10)
To do so, we have to define all our variables as (final)
Also, not to forget the setters inside the class, all variables in an instance shall be defined while instantiation, making it an immutable instance of an immutable class. And in case I need to make any change in any attribute, I shall create a new instance of this class. And even though it may seem consuming for the memory, it is way better in debugging the errors and tracking them to know which instance specifically fails.
Functional programming rules - Functional Purity
Same function, and same input, shall return the same output. Although this seems very logical, this may get broken if the previous principle is not implemented.
We have a class (Person) with an attribute (name).
Person person = new Person();
person.setName("Mohamed");
person.getName(); //Mohamed
person.setName("Ali");
person.getName(); //Ali
Same instance, same function. However, we are getting different results. By implementing immutability, this shall be achieved as well.
Functional programming rules - First-Class functions
In programming languages, being first-class means that you can be
A) Defined B) Passed as an arg C) Returned from another function
Previously -And I mean before Java 8- functions have never been first-class, but now they can perform all the above.
We can do the following
//Defining function
Function<Integer, String> myFunction = x -> "The number is: " + x;
System.out.println(myFunction.apply(10)); //prints (The number is: 10)
/////////////
//Passing function as arg
Integer myMethod (Function<Integer, String> myFunc) {
System.out.println(myFunc.apply(20));
}
myMethod(myFunction); // //prints (The number is: 10)
/////////////
//Returning function
Function<Integer, Function<Integer, Integer> multiply = x -> y -> x * y;
Function<Integer, Integer> multiplyBySix = multiply.apply(6); //Returns a function
multiplyBySix.apply(5); //Returns 30 --> 6 * 5
Since it's a bit confusing and hard to imagine in Java, I'm arranging another article to elaborate further on the implementations of those principles in Java, along with some code examples on Git to be available.
Conclusion
In its attempts to be as updated as it can, Java is trying to add the declarative paradigm to its adorable features, it started from Java 8 (March 2014) and is still ongoing. Nothing is good, nothing is bad. Imperative has its pros and cons, as well as declarative. You as a software engineer have to be familiar with both of them and know when and how to precisely use any of them to get the best of both worlds!
A following article will have more coding details about the implementation of FP in Java
You can find more code examples on this repo