Java 8 — Lambda Expression and Functional Interface | Code Factory
Index Page : Link
Reference Link : Link
Donate : Link
What is Lambda (λ) Expressio? How to write Lambda (λ) Expression?
- It is Anonymous function, not having name, not having modifier, not having any return type
e.g.1
() -> { System.out.println("Code Factory"); }
e.g.2
// Normal Method :
public void add(int a, int b) {
System.out.println(a + b);
}//Lambda Expression :
(int a, int b) -> { System.out.println(a + b); }
e.g.3
// Normal Method :
public int getLength(String s) {
return s.length();
}//Lambda Expression :
(String s) -> { return s.length(); }
- In the Lambda (λ) Expression body if only one statement is there then curly braces ({}) are optional
e.g.1
// Normal Method :
public void m1() {
System.out.println("Code Factory");
}//Lambda Expression :
() -> { System.out.println("Code Factory"); }
OR
() -> System.out.println("Code Factory");
e.g.2
// Normal Method :
public void add(int a, int b) {
System.out.println(a + b);
}//Lambda Expression :
(int a, int b) -> { System.out.println(a + b); }
OR
// Below statement also called Type Inference
(a, b) -> System.out.println(a + b);
e.g.3
// Normal Method :
public int getLength(String s) {
System.out.println(s.length());
}//Lambda Expression :
(String s) -> { return s.length(); }
OR
(s) -> return s.length();
OR
(s) -> s.length()
OR
s -> s.length()
Characteristics/Properties of Lambda (λ) Expression :
(1) A λ-Expression can take any number of parameter
e.g.
() -> System.out.println("Code Factory");
(s) -> s.length();
(a, b) -> System.out.println(a + b);
(2) If multiple parameters present then there parameters shouls be seperated with comma (,)
e.g.
(a, b) -> System.out.println(a + b);
(3) If only one parameters available then parenthesis are optional
e.g.
(s) -> s.length(); TO s -> s.length();
(4) Usually we can specify the type of parameters of compiler expect the type based on context, then we can remove type, called type inference
e.g.
(int a, int b) -> System.out.println(a + b);
TO
(a, b) -> System.out.println(a + b);
(5) Similar to method body, λ-Expression body can contain any number of statements. If multiple statements are there then we should enclose within curly braces
e.g
() -> {
stmt1;
stmt2;
}
(6) If body contains only one statement then curly braces are optional
e.g
() -> System.out.println("Code Factory");
(7) If λ-Expression return something then we can remove return keyword
e.g
s -> s.length();
Functional Interface :
- Interface which contains only single/one abstract method is called Functional Interface
e.g.
Runnable -> contains only run() method
Callable -> contains only call() method
ActionListener -> contains only actionPerformed() method
Comparable -> contains only compareTo() method
- Functional Interface may have any number of default and static methods, restriction is only applicable for abstract method.
// right Functional Interface ✓
interface Interf {
public void m1();
default void m2() { }
public static void m3() { }
}// wrong Functional Interface X
interface Interf {
public void m1();
public void m2();
}
@FunctionalInterface :
(1)
// valid ✓
package com.codeFactory.lambdaExpression;@FunctionalInterface
interface Interf {
public void m1();
default void m2() { };
public static void m3() { };
}
(2)
// not valid X
package com.codeFactory.lambdaExpression;@FunctionalInterface
interface Interf {
public void m1();
public void m2();
}/*
Unexpected @FunctionalInterface annotation
@FunctionalInterface
^
Interf is not a functional interface
multiple non-overriding abstract methods found in interface Interf
1 error
*/
(3)
// not valid X
package com.codeFactory.lambdaExpression;@FunctionalInterface
interface Interf {
}/*
Unexpected @FunctionalInterface annotation
@FunctionalInterface
^
Interf is not a functional interface
no abstract method found in interface Interf
1 error
*/
Functional Interface with inheritance :
(1) If an interface extends Functional Interface and child interface does not contain any abstract method, then child interface is always Functional Interface
// valid ✓
package com.codeFactory.lambdaExpression;@FunctionalInterface
interface InterfP {
public void m1();
}@FunctionalInterface
interface InterfC extends InterfP {
}
(2) In the child interface, we can define exactly same parent interface abstract method
// valid ✓
package com.codeFactory.lambdaExpression;@FunctionalInterface
interface InterfP {
public void m1();
}@FunctionalInterface
interface InterfC extends InterfP {
public void m1();
}
(3) In the child interface we can’t define any new abstract methods otherwise we will get CE
// not valid X
package com.codeFactory.lambdaExpression;@FunctionalInterface
interface InterfP {
public void m1();
}@FunctionalInterface
interface InterfC extends InterfP {
public void m2();
}/*
Unexpected @FunctionalInterface annotation
@FunctionalInterface
^
InterfC is not a functional interface
multiple non-overriding abstract methods found in interface InterfC
1 error
*/
(4) Child interface is normal interface so it will successfully compile
// valid ✓
package com.codeFactory.lambdaExpression;@FunctionalInterface
interface InterfP {
public void m1();
}interface InterfC extends InterfP {
public void m2();
}
Invoking Lambda Expression By using Functional Interface :
(1)
without λ-Expression :
package com.codeFactory.lambdaExpression;interface Interf {
public void m1();
}class Demo implements Interf {
public void m1() {
System.out.println("m1() method implementation");
}
}public class Test {
public static void main(String... args) {
Interf i = new Demo();
i.m1();
}
}
with λ-Expression :
package com.codeFactory.lambdaExpression;interface Interf {
public void m1();
}public class Test {
public static void main(String... args) {
Interf i = () -> System.out.println("m1() method implementation");
i.m1();
}
}
(2)
without λ-Expression :
package com.codeFactory.lambdaExpression;interface Interf {
public void add(int a, int b);
}class Demo implements Interf {
public void add(int a, int b) {
System.out.println(a + b);
}
}public class Test {
public static void main(String... args) {
Interf i = new Demo();
i.add(10, 20);
i.add(100, 200);
}
}
with λ-Expression :
package com.codeFactory.lambdaExpression;interface Interf {
public void add(int a, int b);
}public class Test {
public static void main(String... args) {
Interf i = (a, b) -> System.out.println(a + b);;
i.add(10, 20);
i.add(100, 200);
}
}
(3)
without λ-Expression :
package com.codeFactory.lambdaExpression;interface Interf {
public int getLength(String s);
}class Demo implements Interf {
public int getLength(String s) {
return s.length();
}
}public class Test {
public static void main(String... args) {
Interf i = new Demo();
System.out.println(i.getLength("Code"));
System.out.println(i.getLength("Factory"));
}
}
with λ-Expression :
package com.codeFactory.lambdaExpression;interface Interf {
public int getLength(String s);
}public class Test {
public static void main(String... args) {
Interf i = (s) -> s.length();
System.out.println(i.getLength("Code"));
System.out.println(i.getLength("Factory"));
}
}
(4)
without λ-Expression :
package com.codeFactory.lambdaExpression;class MyRunnable implements Runnable {
@Override
public void run() {
for(int i=0; i<5; i++) {
System.out.println("Child Thred.");
}
}
}public class Test {
public static void main(String... args) {
Runnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
for(int i=0; i<5; i++) {
System.out.println("Main Thred.");
}
}
}
with λ-Expression :
package com.codeFactory.lambdaExpression;public class Test {
public static void main(String... args) {
Runnable r = () -> {
for(int i=0; i<5; i++) {
System.out.println("Child Thred.");
}
};
Thread t = new Thread(r);
t.start();
for(int i=0; i<5; i++) {
System.out.println("Main Thred.");
}
}
}
Functional Interface Summary :
(1) It should contains exactly one abstract method (SAM : Single Abstract Method)
(2) It can contains any number of default and static methods
(3) It acts as a type for λ-Expression
e.g. Interf i = () -> System.out.println("Code Factory");
----------- -------------------------------
type λ-Expression
(4) It can be used to invoce λ=Expression
e.g. i.m1()
Case 1 : Why Funtional Interface should contains only one abstract method?
- Purpose of Functional Interface is to invoke/call Lambda (λ) Expression. Lambda (λ) Expression should map to method of interface. So interface contain none or multiple abstract method then there is a problem in mapping thats why functional interace contains only one abstract method.
Case 2 : What is the advantage of @FunctionalInterface annotation?
- To provide extra information.