Java Functional Programming : 1. Introduction

This is the multi part series on Java Functional Programming 


1. Introduction

As per Wikipedia – “In computer science, functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.Lambda Calculus was first formulated by Alonzo Church in 1930. Functional Programming finds its roots in the Lambda Calculus.
Let us see a quick comparison between the two programming paradigms – Imperative and Functional. This is independent of Java programming language and will help us build the concepts later.

Difference Between Imperative & Functional Languages

Imperative Language
Functional Language
Point 1
The assignments can change over the course of program execution.
A reference is associated with only one value, they do not change, are immutable
Point 2
They are dependent on the order in which the elements are evaluated.
 There is no necessary execution order. Of course, the programs must be executed in an order, but they do not alter the outcome. This is one of the strengths of functional programming.
Point 3
Iterations are usually done by value reassignment.
Iterations are achieved by making recursive calls to the function.
Point 4
Allows only primitive data and object reference
Functional languages allow functions to be treated as values (or references) along with primitives and objects

Let us review the difference with an example. Let us say you iteratively take first 4 integers (starting from 1) and double those values and print them. This is how you would do it in Java.


       public void doubleInt(){
              for (int i=1; i<=4; i++){
                     System.out.print(2*i);
              }
       }

And these are the numbers that get printed.
(2, 4, 6, 8)
What you have done is : taken a number -> doubled it -> printed it, and then went back to the loop, assigning the variable with the next number and repeating the process, till the end condition is achieved. The code could also be written as (though it is not recommended) below to show the steps.


       public void doubleIntBlown(){
              int i=1;                         // initialized a value for a variable
              for (;;){
                     if (!(i<=4)){             // checking for a filter to exit
                           break;
                     }
                     int j = 2*i;              // doubled the number
                     System.out.print(j);      // and printed it
                     i = i+1;                  // re-assigned a new value
              }
       }


If this were to be done using the functional programming paradigm, this is how it would be written (not using the Lambda Expressions for now), basically we can write it simply as:
(doubleOf ( take 4 (integers)))
The statement contains one constant 4, and statements. You really don’t need any variable (like “i”, in the example above) to resolve this. Actually most functional programming languages would have a similar constructs. These are statements are evaluated step by step, one function at a time. So the first step is:
(doubleOf ( take 4 (1, 2, 3, ………..)))
If you think it is copy and paste, this is what precisely happens in most of the programs. The next step becomes:
(doubleOf (1, 2, 3, 4))
What we have done is filtered the numbers to first 4, from an integer set. Now we will double the numbers, and get the final output as:
(2, 4, 6, 8)
Notice that there are no variables needed, and so don’t have to worry about the assignments. We instead passed functions like – integers, take and doubleOf in the program (Point 4, above). If you could look into the memory structure of the program you’d find that each element which has been initialized has retained its values till the end. They have not changed. This is indeed a necessary attribute of functional programming and “Referential Transparency”.  It means that the function must always return the same values if its input is the same. This also implies that the function should be dependent on only the values which are passed within in, and not on anything else. Functional programming mandates that the objects created in the process are immutable and do not change over the course of its execution (Point 1, above). Since the method call do not depend on assigned values, they are also independent of the order in which they are executed (Point 2, above). That is we could have first doubled the values and then taken the first 4 values from the doubled numbers, and would have got the same result. That is:
(doubleOf ( take 4 (integers)))
is equivalent to the statement below and the order does not matter.
(take 4 (doubleOf (integers)))
We would keep revisiting the functional programming as we study the “Lambda Expressions”, and as we dive deeper in Java’s functional programming constructs. One reason why functional programming is important is the way processing happens on the computers. Computers have reached a threshold on the processing speeds, and we are adding to more processing power by adding more cores. Who knows how many cores future computers would have. Java is perhaps bracing up for that. Keeping objects immutable is the only way where we could leverage the power of “parallel” processing. When we are sure that all others threads which are accessing a memory area, are not allowed to modify it, we can work parallely with those values. In case those values are modified, then we have to use “synchronization” to make sure only one thread has access to it one point of time. But we already know, making something “synchronized” comes with the cost of efficiency of execution.
Let us see a java code on how the same can be achieved using the lambda expressions in Java. Do not worry if you don’t get it now. We shall come back to it many times, till we are clear on everything mentioned in the code. This is just for the sake of completion and we shall detail this after we understand what a “Lambda Expression” means:


// created an expression to filter the numbers
// choose top 4 integers
Predicate<Integer> filter = (i) -> i <= 4;
             
// created an expression to double the number
UnaryOperator<Integer> dInt = (i) -> 2*i;           
             
// get a list of integers say 1-10 (it was infinite in the above example),
List<Integer> iList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
             
// and then try to filter it using streams
Stream<Integer> iStream = iList.stream();
             
// the actual operation, where you first filtered and then applied the operator
iStream.filter(filter).map(dInt).forEach(System.out::print);                   


Line 1 of code: Define an expression to get the numbers less than 4, this is for filtering
Line 2 of code: Define an expression to double the number
Line 3 of code: Get a list of integers starting 1 to 10 (or more if you please)
Line 4 of code: Get a stream of integers defined above
Line 4 of code: Filter the numbers double it and print the values

And this is printed when the above code snippet is executed - 2468
You can write all this in just one line, without even declaring variables.


 List<Integer> iList2 = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
 iList2.stream().filter(i -> i <=4).map(i -> 2*i).forEach(System.out::print);  




Next (Lambda & Functional Interfaces) >>

Comments

Popular posts from this blog

Java Generics - 7. Upper and Lower Bounds

Java Functional Programming : 3. The java.util.function Library

Java Generics - 3. Multiple bounding