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() {@Overridepublic void actionPerformed( ActionEvente ){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> () {@Overridepublic int compare(Stringa,Stringb){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