Thinking of Lambda


Many form of Lambda expression in Java

General form: () -> {} : in ‘()’ is parameter(s), in `{}’ is function

  • complete form:
(int a, int b) -> {
    System.out.println(a + b);
}
  • without parameter type:
(a, b) -> {
    System.out.println(a + b);
}
  • without Parentness: where there is only 1 parameter:
value -> {
    System.out.println(value);
}
  • without Brace curly: if your function can be 1 liner
value -> System.out.println(value);

Where to use Lamdba expression in Java

  • replace anonymous class

If we have interface like below:

    public interface Tester{
        public void test(String s);
    }

When we need to implement it, we can use anonymous class:

Tester testerImp = new Tester(){
    @Override
    public void test(String s){
        System.out.println(s);
    }
};

then implements in the main method:

public class TestLambda{

    public boolean verify(String s, Tester t){
        return t.test(s);
    }

    public static void main(String[] args){
        TestLambda obj = new TestLambda();

        Tester testerImp = new Tester(){
            @Override
            public void test(String s){
                System.out.println(s);
            }
        };

        boolean result = obj.verify("Test Successful", testerImp);

        System.out.println(result);

    }
}

now we can use just 1 line lambda replace the testerImp class:


public class TestLambda{

    public boolean verify(String s, Tester t){
        return t.test(s);
    }

    public static void main(String[] args){
        TestLambda obj = new TestLambda();

        boolean result = obj.verify("Test Successful", s -> System.out.println(s));

        System.out.println(result);

    }
}
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);

you implement logic in the this test() method, and return true of false, then use it in the stream() with lambda format, in following example, we define a predicate class that can be used to filter different Person, here is the person class define:

public class Person{
    public int age;
    public String name;
    public boolean isFemale;

    //getter and setter, and constructor ignored
}

we can create predicate methods for filtering (you can define them in the Person class)

public static Predicate<Person> isFemale(){
    return e -> e.isFemale;
}

then you can implements the Predicate:

...
List<Person> persons = new ArrayList();
//add person into list
...
//add all the female person into new list
List<Person> females = persons.stream().filter(isFemale).collect(Collectors.toList());

Lambda is announymous function of Function

Where you can use lamdba, actually is using java.util.Function interface. Function has following type:

  • BiFunction: 2 parameters and 1 return value.
  • Supplier: no parameter Supplier is kind of “next available” containter, eg, you have list of ports can user on server, when start multi thread applications, you can one-by-one (with lock) to get ports available from the list.

  • Consumer: 1 parameter but no return value
  • Predicate: 1 parameter and return value is boolean
  • Operator: parameter and return value are same type and number

2 steps to use Function

  1. Define Function<T, R> T is paramter, R is return value.
  2. Apply R.apply

3 forms of Function

  1. Use class definition
    public class getStringLength implements Function<String, Integer> {
        public Integer apply(String string){
            return string.length();
        }
    }

    public void implement(){
        Function<String, Integer> functionClass = new getStringLength();
        System.out.println(functionClass.apply("length counter"));
    }

  1. Use Annonymous Class
    //Annonymous class
    Function<String, Integer> getStringLength = new Function<String, Integer>() {
        @Override
        public Integer apply(String s) {
            return s.length();
        }
    };

    System.out.println(getStringLength.apply("length counter"));
  1. Use Lamdba
    Function<String, Integer> getStringLengthLamdba = (s) -> {return s.length();};
    System.out.println(getStringLengthLamdba.apply("length counter"));

Use Supplier for lazy inialization

Supplier can perform lazy initialization

public class SparkSubmitter {
   private final SimpleSparkEtlFilWatcherConfig.SparkConfig sparkConfig;
   private final Supplier<SparkLauncher> sparkLauncherSupplier;

   public SparkSubmitter(SimpleSparkEtlFilWatcherConfig config){
      this.sparkConfig = config.getSparkConfig();
      this.sparkLauncherSupplier = SparkLauncher::new;
   }

   public CompletableFuture<String> process(SimpleSparkEtlFilWatcherConfig.ExtractConfig extractConfig, SimpleSparkEtlFilWatcherConfig.LoadConfig loadConfig){
      SparkLauncher launcher = sparkLauncherSupplier.get();
   }