0% found this document useful (0 votes)
29 views32 pages

Lambda Notes

A functional interface in Java is defined as an interface with exactly one abstract method, allowing for any number of default or static methods. Java 8 introduced functional interfaces to support lambda expressions, which provide a concise way to implement single-method interfaces. Examples of functional interfaces include Predicate, Function, Consumer, Supplier, and their variations such as BiFunction and BiConsumer, which facilitate functional programming and enhance code readability.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views32 pages

Lambda Notes

A functional interface in Java is defined as an interface with exactly one abstract method, allowing for any number of default or static methods. Java 8 introduced functional interfaces to support lambda expressions, which provide a concise way to implement single-method interfaces. Examples of functional interfaces include Predicate, Function, Consumer, Supplier, and their variations such as BiFunction and BiConsumer, which facilitate functional programming and enhance code readability.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 32

Key points about the functional interface:

1. An Interface that contains exactly one abstract method is known as


a functional interface.
2. It can have any number of default, static methods but can contain
only one abstract method. It can also declare the methods of the object
class.
3. Functional Interface is also known as Single Abstract Method Interfaces or
SAM Interfaces. It is a new feature in Java 8, which helps to achieve a
functional programming approach.
4. A functional interface can extend another interface only when it does not
have any abstract method.
5. The Java API has many one-method interfaces such as Runnable, Callable,
Comparator, ActionListener, and others. They can be implemented and
instantiated using anonymous class syntax.

Examples of Custom Functional Interface


Create a custom Sayable interface is a functional interface annotated
with @FunctionalInterface.
The @FunctionalInterface annotation indicates that an interface is a functional
interface and contains exactly one abstract method.

Custom Functional Interface Example


Let's create a Sayable interface annotated
with @FunctionalInterface annotation.

@FunctionalInterface
interface Sayable{
void say(String msg); // abstract method
}

Let's demonstrate a custom functional interface via the main() method. We


use Lambda expression to implement functional interfaces:

public class FunctionalInterfacesExample {

public static void main(String[] args) {

Sayable sayable = (msg) -> {


System.out.println(msg);
};
sayable.say("Say something ..");
}
}
Java 8 Predefined-Functional Interfaces
Java 8 provides predefined functional interfaces to deal with functional
programming by using lambda and method references.
Let's discuss Java Predefined-Functional Interfaces with examples.
Let's first create a Person class, we use this Person class is used to demonstrate
Predefined-Functional Interfaces examples.

public class Person {


private String name;
private int age;

public Person(String name, int age) {


super();
this.name = name;
this.age = age;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}

public int getAge() {


return age;
}

public void setAge(int age) {


this.age = age;
}
}

Predicate Functional Interface


We need a function for checking a condition. A Predicate is one such function
accepting a single argument to evaluate a boolean result.

It has a single method test that returns the boolean value.

Predicate interface from JDK 8: Let's look at the internal implementation of


the Predicate interface. Predicate interface contains exactly one abstract
method test(T t). Note that it also contains default, static methods.

@FunctionalInterface
public interface Predicate<T> {
/**
* 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);

default Predicate<T> and(Predicate<? super T> other) {


Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}

default Predicate<T> negate() {


return (t) -> !test(t);
}

default Predicate<T> or(Predicate<? super T> other) {


Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}

static <T> Predicate<T> isEqual(Object targetRef) {


return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}

Let's create an example to demonstrates the usage of the Predicate functional


interface:

public class PredicateExample {


public static void main(String[] args) {
Predicate < Person > predicate = (person) -> person.getAge() > 28;
boolean result = predicate.test(new Person("ramesh", 29));
System.out.println(result);
}
}

Function Functional Interface


It represents a function that accepts one argument and returns a result.
Function interface from JDK 8: Let's look at the internal implementation of
the Function interface. The function interface contains exactly one abstract
method apply(T t). Note that it also contains default, static methods.

@FunctionalInterface
public interface Function<T, R> {
R apply(T t);

default <V> Function<V, R> compose(Function<? super V, ? extends T>


before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}

default <V> Function<T, V> andThen(Function<? super R, ? extends V>


after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}

static <T> Function<T, T> identity() {


return t -> t;
}
}

Let's create an example to demonstrates the usage of


the Function functional interface:

import java.util.function.Function;

public class FunctionExample {

public static void main(String[] args) {


// convert centigrade to fahrenheit
Function < Integer, Double > centigradeToFahrenheitInt = x -> new
Double((x * 9 / 5) + 32);

// String to an integer
Function < String, Integer > stringToInt = x -> Integer.valueOf(x);
System.out.println(" String to Int: " + stringToInt.apply("4"));

Function < PersonEntity, PersonDTO > function = (entity) -> {


return new PersonDTO(entity.getName(), entity.getAge());
};
PersonDTO personDTO = function.apply(new PersonEntity("ramesh",
20));
System.out.println(personDTO.getName());
System.out.println(personDTO.getAge());
}
}

class PersonEntity {
private String name;
private int age;

public PersonEntity(String name, int age) {


super();
this.name = name;
this.age = age;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}

public int getAge() {


return age;
}

public void setAge(int age) {


this.age = age;
}
}

class PersonDTO {
private String name;
private int age;

public PersonDTO(String name, int age) {


super();
this.name = name;
this.age = age;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}

public int getAge() {


return age;
}

public void setAge(int age) {


this.age = age;
}
}
Supplier Functional Interface
Represents a supplier of results.
Supplier interface from JDK 8: Let's look at the internal implementation of
the Supplier interface. The supplier interface contains exactly one abstract
method get(T t). Hence we can apply lambda expression to it.

@FunctionalInterface
public interface Supplier<T> {

/**
* Gets a result.
*
* @return a result
*/
T get();
}

Let's create an example to demonstrates the usage of


the Supplier functional interface:

import java.util.function.Supplier;

public class SuppliersExample {

public static void main(String[] args) {

Supplier<Person> supplier = () -> {


return new Person("Ramesh", 30 );
};

Person p = supplier.get();
System.out.println("Person Detail:\n" + p.getName() + ", " +
p.getAge());
}
}

Consumer Functional Interface


It represents an operation that accepts a single argument and returns no result.
Consumer interface from JDK 8: Let's look at the internal implementation of
the Consumer interface. The consumer interface contains exactly one abstract
method accept(T arg0). Hence we can apply lambda expression to it.

@FunctionalInterface
public interface Consumer<T> {
void accept(T arg0);

default Consumer<T> andThen(Consumer<? super T> arg0) {


Objects.requireNonNull(arg0);
return (arg1) -> {
this.accept(arg1);
arg0.accept(arg1);
};
}
}

Let's create an example to demonstrates the usage of


the Consumer functional interface:

public class ConsumersExample {

public static void main(String[] args) {


List<Person> listOfPerson = new ArrayList<Person>();
listOfPerson.add(new Person("abc", 27));
listOfPerson.add(new Person("mno", 26));
listOfPerson.add(new Person("pqr", 28));
listOfPerson.add(new Person("xyz", 27));

listOfPerson.forEach((person) -> {
System.out.println(" Person name : " + person.getName());
System.out.println(" Person age : " + person.getAge());
});

// Second example
Consumer<Person> consumer = (person) -> {
System.out.println(person.getName());
System.out.println(person.getAge());
};
consumer.accept(new Person("Ramesh", 30));
}
}

BiFunction Functional Interface


It represents a function that accepts two arguments and returns a result.
To define lambdas with two arguments, we have to use additional interfaces that
contain the “Bi” keyword in their names: BiFunction, ToDoubleBiFunction,
ToIntBiFunction, and ToLongBiFunction.
BiFunction interface from JDK 8: Let's look at the internal implementation of
the BiFunction interface. BiFunction interface contains exactly one abstract
method apply(T arg0, U arg1). Hence we can apply lambda expression to it.

@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T arg0, U arg1);

default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends


V> arg0) {
Objects.requireNonNull(arg0);
return (arg1, arg2) -> {
return arg0.apply(this.apply(arg1, arg2));
};
}
}

Let's create an example to demonstrates the usage of


the BiFunction functional interface:

public class BiFunctionExample {

public static void main(String[] args) {

BiFunction<Person, Person, Integer> biFunction = (p1,p2) -> {


return p1.getAge() + p2.getAge();
};

int totalAge = biFunction.apply(new Person("Ramesh", 10),


new Person("ram", 10));
System.out.println(totalAge);

}
}

BiConsumer Functional Interface


It represents an operation that accepts two input arguments and returns no
result.
BiConsumer interface from JDK 8: Let's look at the internal implementation of
BiConsumer interface. BiConsumer interface contains exactly one abstract
method accept(T arg0, U arg1). Hence we can apply lambda expression to it.

@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T arg0, U arg1);

default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> arg0)


{
Objects.requireNonNull(arg0);
return (arg1, arg2) -> {
this.accept(arg1, arg2);
arg0.accept(arg1, arg2);
};
}
}

Let's create an example to demonstrates the usage of


the BiConsumer functional interface:

public class BiConsumersExample {

public static void main(String[] args) {

BiConsumer<Person, Person> biConsumer = (p1, p2) -> {


System.out.println(" print first persion");
System.out.println(p1.getName());
System.out.println(" print second persion");
System.out.println(p2.getName());
};

biConsumer.accept(new Person("Ramesh", 10), new Person("ram", 10));


}
}

BiPredicate Functional Interface


This interface represents a predicate that takes two arguments.
This is how the interface is defined:
@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u);
// Default methods are defined also
}

The below example demonstrates the usage of the BiPredicate functional


interface. Note the comments are self-descriptive.

package com.javaguides.java.functionalinterfaces;

import java.util.function.BiPredicate;

public class BiPredicateDemo {


public static void main(String[] args) {

// anonymous class implements BiPredicate interface


BiPredicate < String, String > predicateObject = new BiPredicate <
String, String > () {

@Override
public boolean test(String s1, String s2) {
return s1.equals(s2);
}
};
System.out.println(predicateObject.test("Ramesh", "Ramesh"));

// Lambda expression implementation


BiPredicate < String, String > biPredicate = (s1, s2) ->
s1.equals(s2);
System.out.println(biPredicate.test("ramesh", "ramesh"));
System.out.println(biPredicate.test("java guides", "Java Guides"));
}
}

Output:

true
true
false

Summary
 A functional interface is an interface that has exactly one abstract
method.
 Since default methods have an implementation, they are not abstract so a
functional interface can have any number of them.
 If an interface declares an abstract method with the signature of one of
the methods of java.lang.Object, it doesn't count toward the functional
interface method count.
 A functional interface is valid when it inherits a method that is equivalent
but not identical to another.
 An empty interface is not considered a functional interface.
 A functional interface is valid even if
the @FunctionalInterface annotation would be omitted.
 Functional interfaces are the basis of lambda expressions.

1. What Are Lambda Expressions?


A lambda expression is simply a function without a name. It can even
be used as a parameter in a function. Lambda Expressions facilitate
functional programming and simplify development greatly.

The main use of Lambda expression is to provide an implementation


for functional interfaces.
Syntax of Lambda Expression

(parameters) -> expression


Or
(parameters) -> { statements; }

The syntax of a lambda expression is characterized by the following


three parts:
Parameters: A lambda expression can contain zero or more
parameters in parentheses.

Arrow Token: The arrow token -> separates the parameters from the
lambda body.

Body: The lambda's body contains expressions or statements


describing the method's functionality.

Here's a simple textual representation:


+------------+ +----+ +-----------------------+
| Parameters | -> | -> | -> | Body (expression/code) |
+------------+ +----+ +-----------------------+

Lambda Expression Syntax Examples

Introduction to Functional Interface

Lambda expression provides an implementation of the Java 8


Functional Interface. An interface that has only one abstract method
is called a functional interface.
Java provides an annotation @FunctionalInterface, which is used to
declare an interface as a functional interface.
If you have used Runnable, Callable, Comparator, FileFilter,
PathMatcher, and EventHandler interfaces in your projects then you
can replace its implementation with Lambda Expression.
Learn Functional Interface in detail - Java 8 Functional Interface.

2. Benefits of Using Lambda Expressions


Conciseness: They allow for a more concise way of expressing
instances of single-method interfaces (functional interfaces).
Functional Programming: They enable functional programming
styles in Java.
Improved Readability: They often make the code more readable,
especially when using functional interfaces.
Flexibility: They can be used wherever a functional interface is
expected.
Interoperability with Streams: They work seamlessly with the
Stream API, allowing for powerful and expressive data processing.

3. Use Cases
Lambda expressions are often used with functional interfaces in
the java.util.function package, such as Predicate, Function, Consumer,
and Supplier. They're also commonly used with the Streams API for
operations like filtering, mapping, and reducing.

4. Java Lambda Expressions Examples

1. Java Simple Lambda Expression Example

Here, we are implementing a Drawable functional interface method


using the lambda expression:

interface Drawable{
public void draw();
}
public class LambdaExpressionExample {
public static void main(String[] args) {
int width=10;
//with lambda
Drawable withLambda=()->{
System.out.println("Drawing "+width);
};
withLambda.draw();
}
}

Output :

Drawing 10

2. Java Lambda Expression Example: No Parameter

If the abstract method takes no parameters and returns no value, the


lambda expression can be written with empty parentheses and a body.
Please refer to the code comments, which indicate that code with
Lambda expression and without Lambda expression.
interface Sayable {
public String say();
}
public class JLEExampleNoParameter {
public static void main(String[] args) {

// without lambda expression


Sayable sayable = new Sayable() {
@Override
public String say() {
return "Return something ..";
}
};
sayable.say();

// with lambda expression


Sayable withLambda = () -> "Return something ..";
withLambda.say();
}
}

3. Java Lambda Expression Example: Single Parameter

If the abstract method takes a single parameter, you can omit the
parentheses around the parameter:
interface Printable {
void print(String msg);
}

public class JLEExampleSingleParameter {

public static void main(String[] args) {


// with lambda expression
Printable withLambda = msg -> System.out.println(msg);
withLambda.print(" Print message to console....");
}
}

Output :

Print message to console....

4. Java Lambda Expression Example: Multiple Parameters

If the abstract method takes multiple parameters, you must include


parentheses around the parameters:
interface Addable{
int add(int a,int b);
}
public class JLEExampleMultipleParameters {

public static void main(String[] args) {


// Multiple parameters in lambda expression
Addable withLambda = (a,b)->(a+b);
System.out.println(withLambda.add(10,20));
// Multiple parameters with data type in lambda expression
Addable withLambdaD = (int a,int b) -> (a+b);
System.out.println(withLambdaD.add(100,200));
}
}

5. Java Lambda Expression Example: Multiple Statements

If the body consists of multiple statements, you must include braces


and use a return statement:
interface IAvarage{
double avg(int[] array);
}
public class JLEExampleMultipleStatements {

public static void main(String[] args) {

IAvarage withLambda = (withLambdaArray) -> {


double sum = 0;
int arraySize = withLambdaArray.length;
System.out.println("arraySize : " + arraySize);
for (int i = 0; i < withLambdaArray.length; i++) {
sum = sum + withLambdaArray[i];
}
System.out.println("sum : " + sum);
return (sum/ arraySize);
};
int[] withLambdaArray = {1,4,6,8,9};
System.out.println(withLambda.avg(withLambdaArray));
}
}

6. Java Lambda Expression Example: Creating Thread

Here is an example of using a lambda expression to replace an


anonymous class for implementing the Runnable interface in Java.
public class JLEExampleRunnable {

public static void main(String[] args) {


//without lambda, Runnable implementation using anonymous class
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(" Runnable example without lambda
exp.");
}
};
Thread thread = new Thread(runnable);
thread.start();
//with lambda
Runnable withLambda = () -> System.out.println(" Runnable
example with lambda exp.");
Thread thread1 = new Thread(withLambda);
thread1.start();
}
}
Output :
Runnable example without lambda exp.
Runnable example with lambda exp.
Without Lambda: The first part of the code creates a Runnable
object using an anonymous class. This object is passed to a Thread,
which is then started. When the thread executes, it prints "Runnable
example without lambda exp." to the console.

With Lambda: The second part of the code shows how to achieve
the same functionality using a lambda expression. Instead of using an
anonymous class, a lambda expression is assigned to a Runnable
variable, withLambda. This lambda expression has the same
functionality as the anonymous class but is much more concise. A
new thread is created with this lambda expression and started, printing
"Runnable example with lambda exp." to the console.

7. Java Lambda Expression Example: Comparator

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class JLEComparatorExample {

public static void main(String[] args) {

List<Person> listOfPerson = new ArrayList<Person>();


listOfPerson.add(new Person("abc", 27));
listOfPerson.add(new Person("mno", 26));
listOfPerson.add(new Person("pqr", 28));
listOfPerson.add(new Person("xyz", 27));

// Without lambda expression.


// Sort list by age
Comparator<Person> comparator = new Comparator<Person>()
{
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
};

Collections.sort(listOfPerson, comparator);

System.out.println(" sort persons by age in ascending order");


for (Person person : listOfPerson) {
System.out.println(" Person name : " + person.getName());
}

// Witht lambda expression.


// Sort list by age

Collections.sort(listOfPerson, (Person o1, Person o2) -> {


return o1.getAge() - o2.getAge();
});
// Use forEach method added in java 8

System.out.println(" sort persons by age in ascending order");


listOfPerson.forEach(
(person) -> System.out.println(" Person name : " +
person.getName()));
}
}
class Person {
private String name;
private int age;

public Person(String name, int age) {


super();
this.name = name;
this.age = age;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}

public int getAge() {


return age;
}

public void setAge(int age) {


this.age = age;
}
}

8. Iterate ArrayList with forEach() method + Lambda Expression


Example

package net.javaguides.collections;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
*
* Java program to demonstrate different ways to Iterate over an
ArrayList in Java
*
*
*/
public class DifferentWaysListIterateProgram {

public static void main(String...args) {

List < String > courses = Arrays.asList("C", "C++", "Core Java",


"J2EE", "Spring", "Hibernate", "Python");

// JDK 8 streaming example lambda expression


courses.stream().forEach(course -> printCourse(course));

// JDK 8 streaming example method reference


courses.stream().forEach(DifferentWaysListIterateProgram::printCou
rse);

// JDK 8 for each with lambda


courses.forEach(course -> printCourse(course));

// JDK 8 for each

courses.forEach(DifferentWaysListIterateProgram::printCourse);
}

// common method to print course


private static void printCourse(String course) {
System.out.println("course name :: " + course);
}
}

9. Iterate HashSet with forEach() method + Lambda Expression


Example

package net.javaguides.collections;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
* Java program to demonstrate different ways to iterate over a Set in
Java
*
* @author Ramesh Fadatare
*
*/
public class DifferentWaysSetIterateProgram {

public static void main(String...args) {

Set < String > courses = new HashSet < String > ();
courses.add("Java");
courses.add("C");
courses.add("C++");

courses.add("Python");
courses.add("Scala");

// JDK 8 streaming example lambda expression


courses.stream().forEach(course -> coursePrinter(course));
// JDK 8 streaming example method reference
courses.stream().forEach(DifferentWaysSetIterateProgram::coursePri
nter);

// JDK 8 for each with lambda


courses.forEach(course -> coursePrinter(course));

// JDK 8 for each


courses.forEach(DifferentWaysSetIterateProgram::coursePrinter);
}

// common method to print course


private static void coursePrinter(String course) {
System.out.println("course name :: " + course);
}
}

10. Iterate HashMap with forEach() method + Lambda


Expression Example

package net.javaguides.collections;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
* This program demonstrate different ways to iterate over a Map in
Java
*
* @author Ramesh Fadatare
*
*/
public class DifferentWaysMapIterateProgram {

public static void main(String...args) {

Map < Integer, String > coursesMap = new HashMap < Integer,
String > ();
coursesMap.put(1, "C");
coursesMap.put(2, "C++");
coursesMap.put(3, "Java");
coursesMap.put(4, "J2EE");
coursesMap.put(5, "Python");
coursesMap.put(6, "Scala");

// JDK 8 for each with lambda


coursesMap.forEach((k, v) -> coursePrinter(k, v));

// JDK 8 for each method reference


coursesMap.forEach(DifferentWaysMapIterateProgram::coursePrinte
r);

// common method to print map key value


private static void coursePrinter(Integer number, String brand) {
System.out.println("course no : " + number + " and course
name : " + brand);
}
}

Summary - key points about lambda expressions

Syntax Simplicity: The syntax of a lambda expression is much more


concise than using anonymous inner classes.
Functional Interfaces: They are used primarily to define the
implementation of an abstract method defined in a functional interface
(an interface with exactly one abstract method).

Parameters and Body: The structure of a lambda consists of a set of


parameters, an arrow ->, and the body of the lambda.

Type Inference: Java's type inference mechanism can often


determine the type of the parameters, allowing you to skip declaring
them.

Return Type: If the body of the lambda consists of a single


expression, the return type will be inferred, and the return keyword is
not needed.

No Access Modifiers: Lambda expressions do not have access


modifiers or a throws clause.

Local Variable Access: Lambdas can access final or effectively final


local variables of the enclosing scope.

Parallel Execution Support: They can be used to facilitate parallel


processing, like in streams.

Enhanced Iteration: They can be used with new iteration methods


provided by the Iterable interface to make iterations over collections
more concise.

Functional Programming Paradigm: Lambda expressions bring


elements of functional programming into Java and enable functional
programming techniques and styles.

Immutable: The variables used inside lambda expressions must be


final or effectively final, making them immutable.
Interoperability with SAM Interfaces: Lambda expressions can be
used wherever a Single Abstract Method (SAM) interface is
expected.

Target Typing: The target type of a lambda expression is determined


by the context in which the lambda is used.

Performance: Lambda expressions are often more performant than


anonymous classes since they are not compiled into separate classes.

Functional Method References: They can be used in combination


with method references to further simplify code where a method
already exists to perform an operation.

No, this Reference: Inside a lambda expression, this keyword refers


to the enclosing instance, not the lambda itself.
Overview
In this tutorial, we will learn Java 8 method references with examples.
Java provides a new feature called method reference in Java 8. Method reference
is used to refer method of the functional interface. It is a compact and easy form
of a lambda expression. Each time when you are using a lambda expression to
just referring a method, you can replace your lambda expression with a method
reference.
In this post, we will learn what is method reference, what are their benefits, and
what are different types of method references.

Kinds of Method References


There are four kinds of method references:

1. Reference to a static method

Example:

ContainingClass::staticMethodName

2. Reference to an instance method of a particular object

Example:

containingObject::instanceMethodName

3. Reference to an instance method of an arbitrary object


of a particular type

Example:

ContainingType::methodName
4. Reference to a constructor

Example:

ClassName::new

Let's discuss these method references one by one with examples.

1. Reference to a Static Method


You can refer to the static method defined in the class. Following is the syntax
and example which describe the process of referring to static method in Java.
Syntax :

ContainingClass::staticMethodName

Example 1: This example shows, how the lambda expression replaced with
method refers to the static method.

package com.java.lambda;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;

public class MethodRefDemo {

public static int addition(int a, int b){


return (a + b);
}

public static void main(String[] args) {

// 2. Method reference to a static method of a class


Function<Integer, Double> sqrt = (Integer input) ->
Math.sqrt(input);
System.out.println(sqrt.apply(4));
Function<Integer, Double> sqrtRef = Math::sqrt;
System.out.println(sqrtRef.apply(4));

BiFunction<Integer, Integer, Integer> functionLambda = (a, b) ->


MethodRefDemo.addition(a, b);
System.out.println(functionLambda.apply(10, 20));

BiFunction<Integer, Integer, Integer> function =


MethodRefDemo::addition;
System.out.println(function.apply(10, 20));
}
}

Example 2: we can also override static methods by referring to methods. In the


following example, we have defined and overloaded three add methods.
import java.util.function.BiFunction;

class Arithmetic {
public static int add(int a, int b) {
return a + b;
}

public static float add(int a, float b) {


return a + b;
}

public static float add(float a, float b) {


return a + b;
}
}

public class ReferenceToStaticMethod2 {


public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> adder1 = Arithmetic::add;
BiFunction<Integer, Float, Float> adder2 = Arithmetic::add;
BiFunction<Float, Float, Float> adder3 = Arithmetic::add;
int result1 = adder1.apply(10, 20);
float result2 = adder2.apply(10, 20.0f);
float result3 = adder3.apply(10.0f, 20.0f);
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
}
}

2. Reference to an Instance Method


Like static methods, you can refer to instance methods also. In the following
example, we are describing the process of referring to the instance method.
Syntax :

containingObject::instanceMethodName

Example 1: In the following example, we are referring to non-static methods.


You can refer to methods by a class object and anonymous object.

public class ReferenceToInstanceMethod {

public void saySomething() {


System.out.println("Hello, this is non-static method.");
}

public static void main(String[] args) {


// Creating object
ReferenceToInstanceMethod methodReference = new
ReferenceToInstanceMethod();
// Referring non-static method using reference
Sayable sayable = methodReference::saySomething;
// Calling interface method
sayable.say();
// Referring non-static method using anonymous object

// You can use anonymous object also


Sayable sayable2 = new ReferenceToInstanceMethod()::saySomething;
// Calling interface method
sayable2.say();
}
}

interface Sayable {
void say();
}

Example 2:

package com.java.lambda;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;

@FunctionalInterface
interface Printable{
void print(String msg);
}

public class MethodRefDemo {

public void display(String msg){


System.out.println(msg);
}

public static void main(String[] args) {

// 1. Method reference to an instance method of an object


MethodRefDemo methodRefDemo = new MethodRefDemo();
Printable printableLambda = (String msg) ->
methodRefDemo.display(msg);
printableLambda.print("Hello");

Printable printable = methodRefDemo::display;


printable.print("Hello");

// using lambda expression


Function<String, String> lowerCaseFunction = (String input) ->
input.toLowerCase();
String result = lowerCaseFunction.apply("Java Guides");
System.out.println(result);

// using method references


Function<String, String> lowerCaseFunctionRef =
String::toLowerCase;
String result1 = lowerCaseFunctionRef.apply("Java Guides");
System.out.println(result1);

}
}

Example 3: In the following example, we are using BiFunction interface. It is a


predefined interface and contains a functional method to apply(). Here, we are
referring to add a method to apply method.

import java.util.function.BiFunction;

class Arithmetic {
public int add(int a, int b) {
return a + b;
}
}

public class InstanceMethodReference3 {


public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> adder = new
Arithmetic()::add;
int result = adder.apply(10, 20);
System.out.println(result);
}
}

3. Reference to an Instance Method of an Arbitrary

Object of a Particular Type


Sometimes, we call a method of argument in the lambda expression. In that
case, we can use a method reference to call an instance method of an arbitrary
object of a specific type.

Syntax :

ContainingType::methodName

Example: The following is an example of a reference to an instance method of


an arbitrary object of a particular type:

String[] stringArray = { "Barbara", "James", "Mary", "John",


"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
4. Reference to a Constructor
You can refer to a constructor by using the new keyword. Here, we are referring
constructor with the help of a functional interface.
Syntax :

ClassName::new

Example 1: The below example demonstrates the usage of method reference to


the constructor.

public class ReferenceToConstructor {


public static void main(String[] args) {
Messageable hello = Message::new;
hello.getMessage("Hello");
}
}

interface Messageable{
Message getMessage(String msg);
}

class Message{
Message(String msg){
System.out.print(msg);
}
}

Example 2: Write the Lambda to convert List into Set and convert Lambda into
method reference:

// 4. reference to a constructor
List<String> fruits = new ArrayList<>();
// Adding new elements to the ArrayList
fruits.add("Banana");
fruits.add("Apple");
fruits.add("mango");
fruits.add("orange");

// Using lambda expression


Function<List<String>, Set<String>> f2 = (nameList) -> new
HashSet<>(nameList);
Set<String> set2 = f2.apply(fruits);
System.out.println(set2);

// Using Method reference


Function<List<String>,Set<String>> f3= HashSet::new;
Set<String> set = f3.apply(fruits);
System.out.println(set);

You might also like