Java Functional Programming – 1 of n

It is not a nice day in the Twin Cities of Minneapolis and St. Paul. It has been raining and snowing on and off all day. I assume the roads are somewhat slippery. The good thing is that we do not have to go anywhere this evening.

One of my goals is to continue learning and experimenting with Java. Experience has taught me that at work one tends to use a limited feature set of the programming language(s) you use. This is why on my own time I like to learn different programming languages and different features so when I design and develop software, I can be quite productive.

We all know that not all languages have the same syntax or features, but with time, most object oriented languages tend to add similar features (not to say the same) with a different name and syntax. That is why I also like to solve problems that require algorithms. Once you have the idea, it does not take too much to implement the algorithm in a different language. This seems to be the trend while developing microservices. The idea is to use the best language for a task.

OK, let me get of the soap box and discuss what I have done so far. I picked up “Java Functional Programming | Full Course | 2020” and watched about a third of the video. That is the part I will be covering in this post. Based on my progress I believe I will generate three to four posts associated with this video.

As usual, my suggestion is to always try as much as you can before you watch or read a section. Then get some help and continue. I am also reading the Get Programming with Node.js book. If I have time today I will try a couple simple things and perhaps generate a post; otherwise will leave it for tomorrow.

The video deals with Declarative programming. Declarative programming is a programming paradigm—a style of building the structure and elements of computer programs—that expresses the logic of a computation without describing its control flow.

Most of us were introduced to Computer Science via Imperative programming. Imperative programming is a programming paradigm that uses statements that change a program’s state. In much the same way that the imperative mood in natural languages expresses commands, an imperative program consists of commands for the computer to perform. Imperative programming focuses on describing how a program operates.

The C programming language uses an imperative model. For example, if we wish to find the minimum value in an unsorted array, we can traverse it keeping track of the current minimum value. If we encounter a lower value, we replace the minimum and continue. This would be: O(n).  If it makes sense one might sort the array: O(n * log(n)) and then perform a binary search: O(log(n)).

Most of software developers are familiar with relational databases and SQL. If we wish to obtain the minimum value of a specific field in a database table, we issue a SQL query. The query is a declarative statement. We tell SQL what we want and SQL figures out how to do it.

If you take a look at the YouTube video, Nelson, the author recommends and uses the IntelliJ IDEA IDE (). I just happen not to have it installed on the Windows machine I was watching the video. Such machine has a very large 4K DELL monitor and it is nice to work on it. I am writing this post on a machine with two smaller side-by-side DELL monitors.

For this small series of posts I will be using the VSCode IDE. I will be using Maven. That is the same tool Nelson uses in the YouTube video. If you use VSCode you need to install an extension. You can read more about it in Java project management in VS Code. Managing a project in VS Code requires the Project Manager for Java extension. The extension helps manage class paths and dependencies, and create new projects, packages, and classes. I am using VSCode v0.14.0.

I am using OpenJDK 11.

Maven project:

   Groupid: com.johncanessa
Artifactid: javafunctional
   Version: 1.0-SNAPSHOT
  Location: C:\Users\johnc\workspace4\JavaFunctional

As previously mentioned, we will create a Maven project. I decided to use the values shown here. You are welcome to use different ones. The location is a folder you keep projects in your computer plus the name for the project. Not much exciting here.

After creating the project, you will find in the target folder some new files and folders.

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.johncanessa</groupId>
  <artifactId>javafunctional</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>javafunctional</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

This is the pom.xml file automatically generated. I edited the <properties> tag. The extension set the values for the maven compiler to 1.7. I changed them to 1.8. That was the only change I made to the file.

package imperative;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * 
 */
public class Main {
    
    
    /**
     * Person class.
     */
    static class Person {

        // **** members ****
        private String name;
        private Gender gender;

        // **** constructor(s) ****
        public Person (String name, Gender gender) {
            this.name = name;
            this.gender = gender;
        }

        // **** getter(s) ****
        public String getName() {
            return this.name;
        }

        public Gender getGender() {
            return this.gender;
        }

        // **** setter(s) ****
        public void setName(String name) {
            this.name = name;
        }

        public void setGender(Gender gender) {
            this.gender = gender;
        }

        // **** other method(s) ****
        @Override
        public String toString() {
            return "{ name: " + name + ", gender: " + gender + " }";
        }
    }


    /**
     * Gender enumerator.
     */
    enum Gender {
        FEMALE, MALE, OTHER
    }

    
    /**
     * Test scaffolding.
     */
    public static void main(String[] args) {
        
        // **** ****
        List<Person> people = List.of(
            new Person("John", Gender.MALE),
            new Person("Gabrielle", Gender.FEMALE),
            new Person("Enzo", Gender.MALE),
            new Person("Natalie", Gender.FEMALE),
            new Person("Gino", Gender.MALE),
            new Person("Carmen", Gender.FEMALE)
        );

        // ???? display people ????
        people.forEach( p -> System.out.println("main <<< p: " + p) );
        System.out.println();


        // **** IMPEARTIVE approach ****
        List<Person> females = new ArrayList<Person>();

        for (Person person : people) {
            if (person.getGender() == Gender.FEMALE)
                females.add(person);
        }

        // **** display females ****
        for (Person female : females) {
            System.out.println("main <<< female: " + female);
        }
        System.out.println();


        // **** DECLARATIVE approach ****
        // Predicate<Person> personPredicate = p -> p.getGender() == Gender.FEMALE;
        Predicate<Person> personPredicate = p -> Gender.FEMALE.equals(p.getGender());

        // **** generate list of females ****
        List<Person> femaleList = people.stream()

            // .filter( p -> p.getGender() == Gender.FEMALE )
            .filter(personPredicate)

            .collect(Collectors.toList());

        // **** display list of females ****
        femaleList.forEach( f -> System.out.println("main <<< f: " + f) );
        System.out.println();

        // **** display females (no additional list) ****
        people.stream()
            .filter( p -> p.getGender() == Gender.FEMALE)
            .forEach( f -> System.out.println("main <<< f: " + f) );
        System.out.println();
    }
}

I created a folder for the imperative package. This structure was defined by the author of the YouTube video. Even though I am using a different IDE, I decided to follow most of the suggestions. You never know when you will run into some section of the code that will not work as expected due to the changes you made to the specified approach.

The import statements will be required as you enter code in this file. Try not to copy and paste them into your code.

Given that this is the imperative package, I was expecting only imperative code. We will implement an imperative and a declarative example.

We will use the Person class in the examples I have seen so far. Each person has a name and gender. We have a single constructor, associated setters and getters, and a toString() method which is used to view the results of the operations we will be performing.

We need to enumerate Gender. In our examples we will only be using the first two.

In the main() method, we declare a list of people and populate it by generating Person objects with random data. It seems we have six records.  We then display the list of people. I added a blank line to separate the list for other output. I will do this on several instances in this post.

The next few lines illustrate the imperative approach. We have to decide how to generate a list of females from the list of people. We start by creating an empty list of females. We then enter a loop to traverse the entire list. On each pass we check if the record is a female. If so we add the record to the female list. When done, we define a loop to traverse the list of females. On each loop we display an element in the list.

The approach is reasonable. It produces the desired results.

For the declarative approach, let’s start by ignoring the first two lines.

We first create a stream of people. The next commented out line filters each person by gender (please ignore the personPredicate line). The following line collects the female records into a list. We can now go back to the people.stream() line and add the name of the list we are generating. Note that we did not have to code explicit steps. We just had to tell Java what we want. Of course we have to specify it in order. Try changing the order of the methods and you might get syntax errors or the results you do not want (there is no free lunch).

We now display the contents of the females list.

The last few lines use a similar yet different approach. If we do not need to keep the list of females for further use, we can just display them without creating the list. You could also include such approach in the declarative section.

Before we get to see the output generated by this code, let’s look at the Predicate<T> function we used to replace the lambda expression we used in the filter() method. We will visit this in more detail in the next set of code later in this post. It seems that we can replace the lambda expression with a variable that is assigned the lambda expression. Are we going back to defining functions? This is not the case. It will become clearer as we progress through this post.

main <<< p: { name: John, gender: MALE }
main <<< p: { name: Gabrielle, gender: FEMALE }     
main <<< p: { name: Enzo, gender: MALE }
main <<< p: { name: Natalie, gender: FEMALE }       
main <<< p: { name: Gino, gender: MALE }
main <<< p: { name: Carmen, gender: FEMALE }        

main <<< female: { name: Gabrielle, gender: FEMALE }
main <<< female: { name: Natalie, gender: FEMALE }  
main <<< female: { name: Carmen, gender: FEMALE }   

main <<< f: { name: Gabrielle, gender: FEMALE }     
main <<< f: { name: Natalie, gender: FEMALE }       
main <<< f: { name: Carmen, gender: FEMALE }        

main <<< f: { name: Gabrielle, gender: FEMALE }     
main <<< f: { name: Natalie, gender: FEMALE }       
main <<< f: { name: Carmen, gender: FEMALE }        

This is the output of our code. We first display the contents of the people list. We can get a count of females.

The next set of lines is associated with the display generated by our imperative code. It seems to work fine.

The next set of lines was generated by the declarative approach code. They match the previous display.

Finally the last set of lines is associated with displaying the female records without the need of an auxiliary list.

Before we proceed, you might wish to experiment changing the code to make sure all is well.

Package java.util.function documents the functional interfaces that provide target types for lambda expressions and method references. We used the Predicate<T> in our last code snippet.

From the Package java.util.function Description:

o Functional interfaces provide target types for lambda expressions and method references.

o Each functional interface has a single abstract method, called the functional method for that functional interface, to which the lambda expression’s parameter and return types are matched or adapted.

o Functional interfaces can provide a target type in multiple contexts, such as assignment context, method invocation, or cast context.

e.g.,

Predicate<T>

It represents a predicate (boolean-valued function) of one argument.

and

Function<T, R>

It represents a function that accepts one argument and produces a result.

package functionalinterface;

import java.util.function.Function;


/**
 * Function<T,R>	
 * Represents a function that accepts one argument and produces a result.
 */
public class _Function {


    /**
     * Test scaffolding.
     */
    public static void main(String[] args) {
        
        // **** initialization ****
        int num = 1;


        // **** increment by 1 ****
        num = incrementByOne(num);

        // **** display result ****
        System.out.println("main <<< num: " + num);


        // **** increment by 1 ****
        num = incrementByOneFunction.apply(num);

        // **** display result ****
        System.out.println("main <<< num: " + num);


        // **** multiply by 10 ****
        num = multiplyBy10Function.apply(num);

        // **** display result ****
        System.out.println("main <<< num: " + num);


        // **** combine the two functions ****
        Function<Integer, Integer> addByOneAndThenMultiplyByTen = 
            incrementByOneFunction.andThen(multiplyBy10Function);

        // **** reset value ****
        num = 4;

        // **** increment by 1 and then multiply by 10 ****
        num = addByOneAndThenMultiplyByTen.apply(num);

        // **** display result ****
        System.out.println("main <<< num: " + num);       
    }


    /**
     * Increments the argument by 1.
     * Takes a single input and outputs the result.
     */
    static int incrementByOne(int num) {
        return ++num;
    }


    /**
     * Increment argument by 1.
     */
    static Function<Integer, Integer> incrementByOneFunction = num -> ++num;


    /**
     * Multiply argument by 10.
     */
    static Function<Integer, Integer> multiplyBy10Function = num -> num * 10;
}

We now move to a new package named functionalinterface. As the name indicates, we will be experimenting with some functional interfaces. AT this time you might want to review the package java.util.function documentation if you are not familiar with it.

In our test scaffolding we define a number and assign it a value.

We then call a function that by the name seems to increment the argument value by one and return it as a result. The result is then displayed. If you look further down the code you will see the implementation of the incrementByOne() function.

Back at the main code, we now take the result from the previous operation and call the apply() method of the implementByOneFunction. Let’s go down and look for the implementByOneFunction object. It is a static Function. It seems to use two arguments but we just see the input which is incremented by one. This Function object appears to be called with a single integer value and returns an integer value. If we go back to the line where it is called, that seems to be the case. The apply() method is part of the Function object.

It seems that we take the current value and make a call to a Function (just guessing) that takes a single integer value and returns an integer result. Let’s go to the declaration and see how the function was implemented. It seems very similar to the previous one. This time we multiply the argument by 10 and return the result. We can check that back in the main code.

We now assign a different value to our num variable.

We combine two of our functions and assign a name to it. This seems to operate like a pipe. It seems that we first increment the value of the argument and then we pass the results to the multiplyBy10Function() which should multiply and return the result.

main <<< num: 2
main <<< num: 3 
main <<< num: 30
main <<< num: 50

If you check the code, we start with a 1, increment it by 1 and then increment it by 1 a second time. The result seems to be correct.

We then assign 4 to the num variable. We add 1 and multiply the result by 10. The expected result is (4 + 1) * 10 = 50 which happens to match the displayed result.

There is a lot more material to cover. For sanity will publish this post. In the next post I will cover a similar amount of material in the video. I will continue with the described format until I finish watching the video. At that time I will post the code in GitHub.

Hope you enjoyed solving this problem as much as I did. The entire code for this project is not available yet in my GitHub repository. It will be made available when this series of posts is completed.

If you have comments or questions regarding this, or any other post in this blog, or if you would like for me to help out with any phase in the SDLC (Software Development Life Cycle) of a project associated with a product or service, please do not hesitate and leave me a note below. If you prefer, send me a private e-mail message. I will reply as soon as possible.

Keep on reading and experimenting. It is the best way to learn, become proficient, refresh your knowledge and enhance your developer toolset!

One last thing, many thanks to all 3,828 subscribers to this blog!!!

Keep safe during the COVID-19 pandemic and help restart the world economy.

John

E-mail:  john.canessa@gmail.com

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.