Java8 Lambda

A block of code that can pass around and to be executed later once or multiple times.

Understand Structure

( ) parentheses : It indicate the parameters (if any) with or without type (if can be inferred), otherwise supply empty parentheses.

Eg: (String str) -> str.isEmpty();    // correct

Eg:  String str -> str.isEmpty();    // wrong, when specify type must include parentheses

{ } return statement : It indicate the logic to be execute

Eg: str -> { return str.isEmpty(); }

Statement enclosed in { } must contains return syntax

Variable name cannot be redefined in {}

interface Engine {
  String getEngine(int d);
}

class VVTI implements Engine {
  public String getEngine(int d) {
    return "Powerful engine";
  }
}

caller( e -> { 
   String e = "Normal engine";  // Wrong, redefine variable is not allow!
   return e;
});

( ) -> { }

Remove Boilerplate Code

button.addActionListener( new ActionListener() {
   
   @Override
   public void actionPerformed( ActionEvent e ) {
       sendCallback(e);
   }

});

ActionListener is single method interface,  and Java already know expected parameter type for single method interface, therefore we can remove:

  • @Override – Annotation
  • Access modifier, return type and method name
  • ActionEvent – parameter
  • Body – open and close bracket
button.addActionListener( new ActionListener() {
   
   @Override
   public void actionPerformed( ActionEvent e ) {
       sendCallback(e);
   }

});

button.addActionListener( e -> sendCallback(e) );

Sorting Example

Arrays.sort( list, new Comparator<String> () {

  @Override
  public int compare(String a, String b) {
      return ( a.length() - b.length() );
  }

}

In Arrays.sort method, java know second arguments, thus remove:

  • @Override – Annotation
  • Access modifier, return type and method name
  • Comparator argument
  • Single return type statement.
  • Body – open and close bracket
Arrays.sort( list, new Comparator<String> () {

  @Override
  public int compare(String a, String b) {
      return ( a.length() - b.length() );
  }
} 

Arrays.sort( list,  (a, b) -> a.length() - b.length() );

Comparator example:

Both return same output :  [a, d, m, y, z]

Java 7:

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("z");
    list.add("y");
    list.add("m");
    list.add("d");
    list.add("a");
		
    Collections.sort(list, new Comparator<String>() {
        @Override
        public int compare(String str1, String str2) {
	    return str1.compareTo(str2);
	 }
    });
		
    System.out.println(list);
}

Java 8:

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("z");
    list.add("y");
    list.add("m");
    list.add("d");
    list.add("a");
		
    Collections.sort(list, (str1, str2) -> str1.compareTo(str2));
		
    System.out.println(list);
}

Annotation @FunctionalInterface

Lambda expression can be use on those object of interface with single abstract method, or functional interface annotation.

The benefit of using the annotation are:

  •  Catches error during compile time
  •  Let’s other developer know this interface is for lambda used.

Runnable interface

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Comparator interface

@FunctionalInterface
public interface Comparator<T> {
     .... 
}

Single abstract method interface

If your interface have more method defined it will not able compile.

public interface MyService {
    abstract void accept(int n);
}

Example 1: Usage in event listeners

Programming in Java UI or GWT may often to deal with button click and listen to the event. Thus, most of the event listeners are defined single method interface.

1, Create a single abstract method interface

public interface ButtonEventListener {
   public void onClick(Button button);
}

2, Object class add event listener

public class MyRadioButton {

   public void addButtonEventListener(ButtonEventListener listener){
	// do something
   }
}

3, Old school way, anonymous implementations

public static void main(String[] args) {
		
   MyRadioButton radioBtn = new MyRadioButton();
   radioBtn.addButtonEventListener(new ButtonEventListener() {
      @Override
      public void onClick(Button button) {
         System.out.println(button.getName() + " button on fire");
      }
   });
}

4, Writing with lambda

public static void main(String[] args) {
		
  MyRadioButton radioBtn = new MyRadioButton();
  radioBtn.addButtonEventListener((listener)->System.out.println("Button on fire"));
} 

Lambda expression

  • Must match with functional interface or single abstract method interface.
  • Expression lambda parameters ( ) match with functional interface method’s parameters.
  • Expression lambda return type { } match with functional interface method’s return type.

Example:

In this example, I create a single method interface and assign the lambda expression to the object.

public interface HighestNumberExpression {
  public int returnHighestNumber(int a, int b);
}

Test code:

public static void main(String[] args) {
		
   HighestNumberExpression formula = (a, b) -> { return ((a > b) ? a : b); };
		
   int result = formula.returnHighestNumber(1,2);
   System.out.println(result);
		
}

Let’s try one more example, to measure time unit different.

public interface TimeUnitDifferent {
    long differentInMinutes(Calendar cal1, Calendar cal2)
}

usage:

public class TimeUnitTest {

  public static void main(String[] args) {
		
    TimeUnitTest demo = new TimeUnitTest();
		
    TimeUnitDifferent different = (Calendar cal1, Calendar cal2) -> { 
      return TimeUnit.MINUTES.convert(cal1.getTimeInMillis() - 
                                      cal2.getTimeInMillis(), 
                                      TimeUnit.MILLISECONDS); 
    };
		
    Calendar noon1pm = Calendar.getInstance();
    noon1pm.set(2016, 04, 11, 13, 00);
		
    Calendar noon12pm = Calendar.getInstance();
    noon12pm.set(2016, 04, 11, 12, 00);
		
    System.out.println("time minutes different: " + demo.check(noon1pm, noon12pm, different) );
		
  }
	
  private long check(Calendar cal1, Calendar cal2, TimeUnitDifferent different) {
    return different.differentInMinutes(cal1, cal2);
  }
}

Method Reference

In lambda, we can shorten the syntax on { } return statement by using method reference.  ClassName::staticMethodName

Math::cos   

-- equivalent lambda --

x->Math.cos(x)

object::instanceMethod

"abc"::toUpperCase

-- equivalent lambda --

() -> "abc".toUpperCase()

Class::instanceMethod

String::toUpperrCase

-- equivalent --

s -> s.toUpperCase()

ClassOrType::new

Employee::new

-- equivalent --

() -> new Employee()

Example, you can print string like

public class TestLamda {

  public static void main(String[] args) {
    String[] words = {"numeric","alphabet"};
    List<String> list = Arrays.asList(words);    
 
    Arrays.sort(words, (first,second) -> first.compareToIgnoreCase(second));
    print(words);
    Arrays.sort(words, String::compareToIgnoreCase);
    list.forEach(x -> System.out.println(x));

    list.forEach(System.out::println); 
  }
	
  public static void print(String[] arr) {
    for (String x : arr) {
      System.out.println(x);
    }
    System.out.println("################");
  }
}

Usage:

The main point of using lambda is deferred execution:

  • Run the code in seperate thread
  • Run the code in multiples times
  • Run the code at the right point in an algorithm (eg comparison operation in sorting)
  • Run the code like event based, such as when button is clicked / data has arrived
  • Run the code when necessary
Java8 Lambda

Leave a Reply

Your email address will not be published. Required fields are marked *

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