Saturday, January 21, 2017

Function as First Class Citizens in Java

Java (in version 8) added support for treating functions as first-class citizens. Before this, Java programmers had to wrap standalone functions with Runnables or other anonymous interface implementation class to be able to refer to them. 

Function as first-class citizen/type/object/entity/value:
Functions can be passed around like any other value!

What this basically means is that-

  •  functions can be passed as arguments to other functions, 
  • functions can be returned as values from other functions, 
  • functions can be assigned to variables 
  • functions can be stored in data structures. 

Before Java 8, Objects and primitives data types were treated as first-class citizens (Classes and Functions were treated as second class as they were not values). But, functions are just as valuable to manipulate and reuse. Java inherited this modern feature from other functional programming languages (like JavaScript, Scala). This will help in improving productivity as programmers now can code at the different level of abstraction. 

Read more in detail about what is first class, here


Lambda expression enables you to provide an implementation of the functional interfaces (which has only one method ) directly inline and they treat the whole expression as an instance of the functional interface. Below, we will see how lambda enables functional interfaces to be treated as first-class objects.


Function As Value

java.util.function package (ref) provides multipurpose functional interfaces which come in handy.


import java.util.function.BiFunction;
import java.util.function.Predicate;

/**
 * Creates Inline lambda functions and stores as variable. And then function can be called directly from variable.
 */
public class FunctionAsValue {
    public static void main(String[] args){
        Predicate<String> predicate = (s) -> s!=null || !s.isEmpty ();
        System.out.println(predicate.test ("geekrai"));

        //static method which confirms to Predicate method signature can be stored in invoked
        Predicate<String> pedicateRef = FunctionAsValue::isNotEmpty;
        System.out.println(pedicateRef.test ("geekrai"));

        //BiFunction accepts two arguments and produces a result
        BiFunction<String, String, String> concat = (s, t) -> s+t;
        System.out.println(concat.apply ("hello", " world"));
    }

    private static boolean isNotEmpty(String s){
        return s!=null || !s.isEmpty ();
    }
}


Output:

true
true
hello world


Function As Parameter




import java.util.function.Function;

/**
 * Illustrates how to pass function as parameter
 */
public class FunctionAsParam {
    public static void main(String[] args){
        //pass function as parameter to transform method
        System.out.println(transform ("geek", "Rai", s -> s.toUpperCase ()));

        Function<String, String> toLower = s -> s.toLowerCase ();

        System.out.println(transform("geek", "Rai", toLower));
    }

    private static String transform(String a, String b, Function<String,String> toUpper){
        if(toUpper != null){
            a = toUpper.apply (a);
            b = toUpper.apply (b);
        }
        return a + b;
    }
}

Output:
GEEKRAI
geekrai

--happy functional programming !!!


No comments:

Post a Comment