Java Functional Programming – 2 of n

Today I woke up a little earlier than usual. I have my alarm set for 06:00 AM, but I was up around 04:45 AM. Read for a while, prepared breakfast and woke up my wife. After breakfast showered and was in my home office by 06:00 AM. I typically work in 2-hour blocks. Break for about 15 minutes and then repeat. For lunch I break for about an hour depending if I need to help my wife with lunch. Typically I help grilling on the deck, but the temperature has dropped and there is snow so I think there will be no more outdoor cooking until next spring.

I have a lot of things planned for the workday. Hopefully I will be able to get most of them done by 06:00 PM.

As I mentioned in my previous post, I am watching “Java Functional Programming | Full Course | 2020” on YouTube. The course is hosted by Nelson from Amigoscode. I am currently about half way done. I expect to be completed with this task over the weekend. During breakfast my wife mentioned that this Saturday morning she will be going out shopping with a friend. Those outings tend to be over shortly before noon. That should give me enough time for two blocks. Will see what happens over the weekend!

Let’s pick up where we left off on the previous post.

The video continues to visit different interfaces in the Package java.util.function documentation. Functional programming blends very well with the Streams API. This post continues to deal with items that will be very helpful with streams.

Function<T,R>	
Represents a function that accepts one argument and produces a result.

BiFunction<T,U,R>	
Represents a function that accepts two arguments and produces a result.

Consumer<T>	
Represents an operation that accepts a single input argument and returns no result.

BiConsumer<T,U>	
Represents an operation that accepts two input arguments and returns no result.

Predicate<T>	
Represents a predicate (boolean-valued function) of one argument.

BiPredicate<T,U>	
Represents a predicate (boolean-valued function) of two arguments.

Supplier<T>	
Represents a supplier of results.

In this post we will deal with examples for the functional interfaces here listed. The idea is to write some code using imperative approaches in common Java functions and then experimenting with the functional / declarative equivalents.

Hello James, thanks for registering phone number: 111.111.1111
Hello James, thanks for registering phone number: ***.***.****

Hello James, thanks for registering phone number: 111.111.1111
Hello James, thanks for registering phone number: ***.***.****

The output seems to show two approaches for two different set of function. In the previous post I started with the code and then showed the output. It seems to me that it might better for us to first look at the output and then associate it with the Java code. If you have a preference, please let me know and I will oblige.

package functionalinterface;

import java.util.function.BiConsumer;
import java.util.function.Consumer;

/**
 * Consumer<T> Represents an operation that accepts a single input argument 
 * and returns no result.
 * 
 * BiConsumer<T,U>	
 * Represents an operation that accepts two input arguments 
 * and returns no result.
 */
public class _Consumer {

    /**
     * Test scaffolding.
     */
    public static void main(String[] args) {
        
        // **** create and greet customer using java function ****
        Customer customer = new Customer("James", "111.111.1111");
        greetCustomer(customer);

        // **** greet customer using java function ****
        boolean showPhone = false;
        greetCustomerV2(customer, showPhone);

        // **** for the looks ****
        System.out.println();


        // **** greet customer using Consumer<> functional interface ****
        greetCustomerConsumer.accept(customer);

        // **** greet customer using BiConsumer<> functional interface ****
        greetCustomerConsumerV2.accept(customer, showPhone);
    }


    /**
     * Greet customer.
     */
    static void greetCustomer(Customer customer) {
        System.out.println("Hello " + customer.getName() + 
            ", thanks for registering phone number: " + customer.getPhone());
    }


    /**
     * Greet customer V2.
     */
    static void greetCustomerV2(Customer customer, boolean showPhone) {
        System.out.println("Hello " + customer.getName() + 
            ", thanks for registering phone number: " + 
            (showPhone ? customer.getPhone() : "***.***.****"));
    }


    /**
     * Greet customer using Consumer<>.
     */
    static Consumer<Customer> greetCustomerConsumer = c -> 
        System.out.println("Hello " + c.getName() + 
        ", thanks for registering phone number: " + c.getPhone());


    /**
     * Greet customer using BiConsumer<>.
     */
    static BiConsumer<Customer, Boolean> greetCustomerConsumerV2 = (c, showPhone) -> 
        System.out.println("Hello " + c.getName() + 
        ", thanks for registering phone number: " + 
        (showPhone ? c.getPhone() : "***.***.****"));


    /**
     * 
     */
    static class Customer {

        // **** class members ****
        private String name;
        private String phone;

        // **** constructor(s) ****
        public Customer(String name, String phone) {
            this.name   = name;
            this.phone  = phone;
        }

        // **** getters and setters ****
        public void setName(String name) {
            this.name = name;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public String getName() {
            return this.name;
        }

        public String getPhone() {
            return this.phone;
        }

        // **** other methods ****
        @Override
        public String toString() {
            return "(name: " + name + ", phone: " + phone + ")";
        }
    }
}

In this section we will deal with the Consumer<> and BiConsumer<> interfaces.

We create a customer object which we use to great by calling a regular Java function. We then use a different regular Java function with added functionality that allows us to display or not the associated phone number. These functions are responsible for the first set of output lines.

The following two functional calls achieve the same results as shown by their output.

Let’s move down and take a quick look at the simple Customer class used in these examples.

The Customer class has two members, a constructor, getter and setters and a toString() method which I believe we did not use. As usual I like to write some code as I am watching the video. I then make changes and see the results. At some point I decided not to display the customer record. I will do it in the code (done) that I will put in GitHub when I finish watching the video.

The greetCustomer() function displays a message with the name and phone number.

The greetCustomerV2() function uses a similar message but the actual phone number may or may not be displayed based on the value of the second argument.

The greetCustomerConsumer() is the functional equivalent to the first function, while the greetCustomerConsumerV2() is the functional equivalent to the second one.

main <<< without Predicate<>:
phone: 091234567890 is valid
phone: 071231231234 is invalid
phone: 09123456789 is invalid

main <<< with Predicate<>:
phone: 091234567890 is valid
phone: 071231231234 is invalid
phone: 09123456789 is invalid

phone: 096124567890 Minneapolis
phone: 09612456789 not Minneapolis
phone: 099524567890 not Minneapolis
phone: 09952456789 not Minneapolis

phone: 096124567890 is valid
phone: 09612456789 is valid
phone: 099524567890 is valid
phone: 09952456789 is invalid

In this example it seems we are attempting to validate a phone number. This is just an example. For this task one should use regular expressions. That said, the first set of four lines performs a validation not using a Predicate<T> while the next four lines uses it.

The rest of the lines are not the best examples, but it provides the proper idea on how to write the code and use it.

package functionalinterface;

import java.util.function.Predicate;

/**
 * Predicate<T> Represents a predicate (boolean-valued function) of one
 * argument.
 * 
 * BiPredicate<T,U>	
 * Represents a predicate (boolean-valued function) of two arguments.
 */
public class _Predicate {
    

    /**
     * Test scaffolding.
     */
    public static void main(String[] args) {
        
        // **** ****
        System.out.println("main <<< without Predicate<>:");
        String phone = "091234567890";
        System.out.println("phone: " + phone + " is " + 
            (isPhoneNumberValid(phone) ? "valid" : "invalid"));

        // **** ****
        phone = "071231231234";
        System.out.println("phone: " + phone + " is " + 
            (isPhoneNumberValid(phone) ? "valid" : "invalid"));

        // **** ****
        phone = "09123456789";
        System.out.println("phone: " + phone + " is " + 
            (isPhoneNumberValid(phone) ? "valid" : "invalid"));

        // **** for the looks ****
        System.out.println();


        // **** with Predicate ****
        System.out.println("main <<< with Predicate<>:");
        phone = "091234567890";
        System.out.println("phone: " + phone + " is " + 
            (isPhoneNumberValidPredicate.test(phone) ? "valid" : "invalid"));
        
        // **** with Predicate ****
        phone = "071231231234";
        System.out.println("phone: " + phone + " is " + 
            (isPhoneNumberValidPredicate.test(phone) ? "valid" : "invalid"));

        // **** with Predicate ****
        phone = "09123456789";
        System.out.println("phone: " + phone + " is " + 
            (isPhoneNumberValidPredicate.test(phone) ? "valid" : "invalid"));

        // **** for the looks ****
        System.out.println();


        // **** ****
        phone = "096124567890";
        System.out.println("phone: " + phone + " " +
            (isPhoneNumberValidPredicate
                .and(isMinneapolisNumberPredicate)
                .test(phone) ? "Minneapolis" : "not Minneapolis"));

        // **** ****
        phone = "09612456789";
        System.out.println("phone: " + phone + " " +
            (isPhoneNumberValidPredicate
                .and(isMinneapolisNumberPredicate)
                .test(phone) ? "Minneapolis" : "not Minneapolis"));           
            
        // **** ****
        phone = "099524567890";
        System.out.println("phone: " + phone + " " +
            (isPhoneNumberValidPredicate
                .and(isMinneapolisNumberPredicate)
                .test(phone) ? "Minneapolis" : "not Minneapolis"));

        // **** ****
        phone = "09952456789";
        System.out.println("phone: " + phone + " " +
            (isPhoneNumberValidPredicate
                .and(isMinneapolisNumberPredicate)
                .test(phone) ? "Minneapolis" : "not Minneapolis"));

        // **** for the looks ****
        System.out.println();
    

        // **** ****
        phone = "096124567890";
        System.out.println("phone: " + phone + " is " +
            (isPhoneNumberValidPredicate
                .or(isMinneapolisNumberPredicate)
                .test(phone) ? "valid" : "invalid"));

        // **** ****
        phone = "09612456789";
        System.out.println("phone: " + phone + " is " +
            (isPhoneNumberValidPredicate
                .or(isMinneapolisNumberPredicate)
                .test(phone) ? "valid" : "invalid"));           
            
        // **** ****
        phone = "099524567890";
        System.out.println("phone: " + phone + " is " +
            (isPhoneNumberValidPredicate
                .or(isMinneapolisNumberPredicate)
                .test(phone) ? "valid" : "invalid"));

        // **** ****
        phone = "09952456789";
        System.out.println("phone: " + phone + " is " +
            (isPhoneNumberValidPredicate
                .or(isMinneapolisNumberPredicate)
                .test(phone) ? "valid" : "invalid"));
    }


    /**
     * Simple phone number validation.
     * One should use regular expressions.
     */
    static boolean isPhoneNumberValid(String phone) {
        return phone.startsWith("09") && phone.length() == 12;
    }


    /**
     * Simple phone number validation using Predicate<>
     */
    static Predicate<String> isPhoneNumberValidPredicate = phone -> 
        phone.startsWith("09") && phone.length() == 12;


    /**
     * Minneapolis Phone number.
     */
    static Predicate<String> isMinneapolisNumberPredicate = phone ->
        phone.substring(2, 5).equals("612");
}

The assumption is that phone numbers have 12 digits and then have to sprat with the digits “09”. We try to find out is we have a valid number for Minneapolis or not.

Please look at the output while we check the code for the functions.

The isPhoneNumberValid() function checks if the phone starts with the sequence “09” and the phone number has 12 digits. If that is the case it returns true.

The isPhoneNumberValidPredicate() if the functional equivalent to the isPhoneNumberValid () function.

Last but not least the isMinneapolisNumberPredicate() checks if the specified substring “612” is in the phone number. It return true if present; otherwise false if not.

Note that because one can connect the valid number and is Minneapolis checks with an OR or an AND, the combine check is not what you would like to use for general checks. Remember that this functional conditions work well with streams.

url ==>jdbc:mysql://localhost:1234/users<==
url ==>jdbc:mysql://localhost:1234/users<==

url: jdbc:mysql://localhost:1234/users
url: jdbc:mysql://localhost:1235/systems
url: jdbc:mysql://localhost:1236/managers

It seems like the first two function calls return the same ULR result. It also seems like a function is returning a list of URLs. Let’s look at the code to see what is happening.

package functionalinterface;

import java.util.List;
import java.util.function.Supplier;

/**
 * Supplier<T> Represents a supplier of results.
 */
public class _Supplier {
    

    /**
     * Test scaffolding.
     */
    public static void main(String[] args) {

        // **** using Java function ****
        String url = getDBConnectionUrl();

        // **** display URL ****
        System.out.println("url ==>" + url + "<==");
        

        // **** using Supplier<String> ****
        url = getDBConnectionUrlSupplier.get();

        // **** display URL ****
        System.out.println("url ==>" + url + "<==\n");


        // **** get and display list of URL connections ****
        getDBConnectionUrlList.get().forEach( u -> System.out.println("url: " + u) );
    }


    /**
     * Common type of function / method.
     */
    static String getDBConnectionUrl() {
        return "jdbc:mysql://localhost:1234/users";
    }


    /**
     * Now using functional interface Supplier<T>.
     * The type could be List<String> or any other object type
     * we would like to get.
     */
    static Supplier<String> getDBConnectionUrlSupplier = 
        () -> "jdbc:mysql://localhost:1234/users";

    
    /**
     * Return a list of URLs using functional programming.
     */
    static Supplier<List<String>> getDBConnectionUrlList =
        () -> List.of(
            "jdbc:mysql://localhost:1234/users",
            "jdbc:mysql://localhost:1235/systems",
            "jdbc:mysql://localhost:1236/managers"
        );
}

We start by getting and displaying the URL returned by a Java function. Using a Supplier<> functional API we have a different function that returns the same result. We then have the functional function getDBConnectionUrlList() which returns a list of URLs.

The first implementation is quite simple. The function returns a hardcoded value.

The second implementation does the same but is designed via the Supplier<> interface.

The last function is also implemented with the Supplier<> API, but it returns a list instead of a single String.

As usual, spend time experimenting and creating your own scenarios. If you get to watch the YouTube video you will be able to tell that I added my own ideas. Some of my experiments were removed because they returned similar results.

Hope you enjoyed solving this problem as much as I did. I will not post the code in a GitHub repository until I finish this set of posts. I believe there will be four.

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,890 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.