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?

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 :

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 :

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 :

// 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 :

// 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 :

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 :

(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.