Method Reference in Java

In the post Lambda expression in Java we have already seen how Lambda expression provides an instance of functional interface and implements the abstract method of the functional interface. Though sometimes, a lambda expression is used just to call an existing method. In those cases you can refer to the existing method by name using Method references in Java. Method reference is a compact and more readable lambda expressions for methods that already have a name.

For example consider the following lambda expression-

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.forEach((Integer a) -> System.out.println(a));

Here lambda expression is just calling an existing method which can be done using method reference making the code more readable and concise.

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.forEach(System.out::println);

Method reference also needs a target type

Java method reference can be termed as a special form of lambda expression as method reference also needs a target type context (a compatible functional interface) and it also creates an instance of functional interface just like lambda expression does. Which also means method reference can only be used for a single method.

Where these two differ is lambda expression can also provide implementation for an abstract method where as method reference refers to an existing method.

Java Method reference syntax

As we have already seen in the example a new double colon operator (::) is added in Java to be used with method reference.

Class or object that contains the method is on the left side of the double colon operator and the name of the method in on the right side of the operator.

Kinds of Method References

There are four kinds of method references in Java

Kind Example
Reference to a static method ContainingClass::staticMethodName
Reference to an instance method of a particular object containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type ContainingType::methodName
Reference to a constructor ClassName::new

Static method reference

Following example shows how to use static method reference in Java.

public class MethodRef {
  public static <T> List<T> filter(List<T> myList, Predicate<T> predicate) {
    List<T> filterdList = new ArrayList<T>();
    for(T element: myList) {
      if(predicate.test(element)) {
        filterdList.add(element);
      }
    }
    return filterdList;
  }
  public static boolean isMoreThanValue(int i) {
    return i > 10;
  }
  public static void main(String[] args) {
    List<Integer> myList = Arrays.asList(25, 5, 17, 1, 7, 14, 9, 11);
    System.out.println("Method call as lambda expression");
    List<Integer> filterdList = filter(myList, (i) -> MethodRef.isMoreThanValue(i));
    System.out.println("Filtered elements- " + filterdList);
    System.out.println("Method call using method reference");
    filterdList = filter(myList, MethodRef::isMoreThanValue);
    System.out.println("Filtered elements- " + filterdList);
  }
}
Output
Method call as lambda expression
Filtered elements- [25, 17, 14, 11]
Method call using method reference
Filtered elements- [25, 17, 14, 11]

In the example static method isMoreThanValue() is called using method reference MethodRef::isMoreThanValue.

In the filter method one of the argument is of type Predicate. Predicate is a functional interface which has an abstract method test() which evaluates this predicate on the given argument and return a boolean value (true or false).

Static method isMoreThanValue() is an implementation of the abstract method test() of the Predicate functional interface. When you make a method call filter(myList, MethodRef::isMoreThanValue), Java can infer from the context that isMoreThanValue() is an implementation for Predicate interface.

Method reference to an instance method

In this case you use an object of the class to refer the method rather than using the class name.

public class MethodRef {
  public <T> List<T> filter(List<T> myList, Predicate<T> predicate) {
    List<T> filterdList = new ArrayList<T>();
    for(T element: myList) {
      if(predicate.test(element)) {
        filterdList.add(element);
      }
    }
    return filterdList;
  }
  public boolean isMoreThanValue(int i) {
    return i > 10;
  }
  public static void main(String[] args) {
    List<Integer> myList = Arrays.asList(25, 5, 17, 1, 7, 14, 9, 11);
    MethodRef obj = new MethodRef();
    System.out.println("Method call as lambda expression");
    List<Integer> filterdList = obj.filter(myList, (i) -> obj.isMoreThanValue(i));
    System.out.println("Filtered elements- " + filterdList);
    System.out.println("Method call using method reference");
    filterdList = obj.filter(myList, obj::isMoreThanValue);
    System.out.println("Filtered elements- " + filterdList);
  }
}
Output
Method call as lambda expression
Filtered elements- [25, 17, 14, 11]
Method call using method reference
Filtered elements- [25, 17, 14, 11]

It is the same example as the static method reference only change is now instance of the class is used for method reference. Methods are also not required to be static now.

Reference to an instance method of an arbitrary object of a particular type

In the previous example specific object of the class is used but you may have a scenario in which you want to specify an instance method that can be used with any object of a given class. In that case method reference will have the following form-

ClassName::instanceMethodName

In this case, the first parameter of the functional interface matches the object that has been used to invoke the method and any other parameters are passed to the method.

In the example there a class Person with fields firstName, lastName, age and you need to get the count of Persons with age greater than 50. In this scenario isAgeGreater() method has to be invoked for all the Person objects.

class Person {
  private String firstName;
  private String lastName;
  private int age;
  public Person(String firstName, String lastName, int age){
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public int getAge() {
    return age;
  }
  // This becomes the abstract method (test) implementation
  // of the functional interface
  boolean isAgeGreater(int age) {
    return this.getAge() > age;
  }
}
@FunctionalInterface
interface TestInterface {
  boolean test(Person person, int age);
}
public class MethodRef {
  public static void main(String[] args) {
    List<Person> tempList = createList();
    int count = ageCounter(tempList, Person::isAgeGreater, 50);
    System.out.println("Person count age greater than 50- " + count);
  }

  static int ageCounter(List<Person> list, TestInterface ref, int age) {
    int count = 0;
    for(Person person : list) {
      // first param becomes the invoking object
      // other parameters are passed to method
      if(ref.test(person, age))
        count++;
    }
    return count;
  }

  private static List<Person> createList(){
    List<Person> tempList = new ArrayList<Person>();
    tempList.add(new Person("Joe","Root", 28));
    tempList.add(new Person("Mathew","Hayden", 42));
    tempList.add(new Person("Richard","Hadlee", 55));
    tempList.add(new Person("Sunil","Gavaskar", 65));
    tempList.add(new Person("Brian","Lara", 45));     
    return tempList;
  }
}

Constructor reference

You can also reference a constructor which is similar to method reference except that the name of the method is new in this case.

Syntax for the constructor reference is as follows-

classname::new

Constructor reference Java example

In the method copyElements() one of the parameter is of type Supplier which is a functional interface defined in java.util.function package. The functional interface Supplier contains one method get that takes no arguments and returns an object. A new ArrayList instance is passed to Supplier as a constructor reference.

public class MethodRef {
  public static void main(String[] args) {
    List<Integer> myList = Arrays.asList(25, 5, 17, 1, 7, 14, 9, 11);
    List<Integer> tempList = copyElements(myList, ArrayList::new);
    System.out.println("Copied list- " + tempList);
  }

  public static List<Integer> copyElements(List<Integer> sourceList, Supplier<List<Integer>> destList) {      
    List<Integer> list = destList.get();
    for (Integer i : sourceList) {
      list.add(i);
    }
    return list;
  }
}

That's all for the topic Method Reference in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

Built-in Functional Interfaces in Java

Post about Functional Interface in Java gives an overview of functional interfaces and how Lambda expressions can be used to implement functional interfaces. At the same time it doesn’t mean whenever you want to use lambda expression you will have to write your own custom functional interface. In Java there are many built-in functional interfaces which cover many different contexts when used with lambda expressions in Java.

Built-in functional interfaces Java package

In Java there is a package java.util.function that defines many general purpose functional interfaces used by the JDK and used by user code as well.

Functional interfaces in this package can be categorized into five types-

  1. Consumer
  2. Function
  3. Predicate
  4. Supplier
  5. Operators that extend Function

Consumer functional interface

java.util.function.Consumer<T> functional interface represents an operation that accepts a single input argument and returns no result. Definition of the Consumer is as given below which consists of an abstract method accept() and a default method andThen()-

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

  default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
  }
}

Here is a list of other pre-defined Consumer functional interfaces sharing the same behavior of consuming the passed value(s) and returning no result.

  • BiConsumer<T,U>- Represents an operation that accepts two input arguments and returns no result.
  • DoubleConsumer- Represents an operation that accepts a single double-valued argument and returns no result.
  • IntConsumer- Represents an operation that accepts a single int-valued argument and returns no result.
  • LongConsumer- Represents an operation that accepts a single long-valued argument and returns no result.
  • ObjDoubleConsumer<T>- Represents an operation that accepts an object-valued and a double-valued argument, and returns no result.
  • ObjIntConsumer<T>- Represents an operation that accepts an object-valued and a int-valued argument, and returns no result.
  • ObjLongConsumer<T>- Represents an operation that accepts an object-valued and a long-valued argument, and returns no result.

See post Java Consumer Functional Interface Examples for examples of Consumer interface and BiConsumer Functional Interface Java Examples for examples of BiConsumer interface

Supplier functional interface

java.util.function.Supplier<T> functional interface represents a function that supplies a result. Supplier interface definition is as given below-

@FunctionalInterface
public interface Supplier<T> {
  T get();
}

Here is a list of pre-defined Supplier functional interfaces sharing the same behavior of supplying a result.

  • BooleanSupplier- Represents a supplier of boolean-valued results.
  • DoubleSupplier- Represents a supplier of double-valued results.
  • IntSupplier- Represents a supplier of int-valued results.
  • LongSupplier- Represents a supplier of long-valued results.

Function functional interface

java.util.function Function<T,R> functional interface represents a function that accepts one argument and produces a result.

Abstract method in this functional interface is apply(Object).

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

Here is a list of other pre-defined Function functional interfaces sharing the same behavior of accepting argument(s) and producing a result.

  • BiFunction<T,U,R>- Represents a function that accepts two arguments and produces a result.
  • DoubleFunction<R>- Represents a function that accepts a double-valued argument and produces a result.
  • DoubleToIntFunction- Represents a function that accepts a double-valued argument and produces an int-valued result.
  • DoubleToLongFunction- Represents a function that accepts a double-valued argument and produces a long-valued result.
  • IntFunction<R>- Represents a function that accepts an int-valued argument and produces a result.
  • IntToDoubleFunction- Represents a function that accepts an int-valued argument and produces a double-valued result.
  • IntToLongFunction- Represents a function that accepts an int-valued argument and produces a long-valued result.
  • LongFunction<R>- Represents a function that accepts a long-valued argument and produces a result.
  • LongToDoubleFunction- Represents a function that accepts a long-valued argument and produces a double-valued result.
  • LongToIntFunction- Represents a function that accepts a long-valued argument and produces an int-valued result.
  • ToDoubleBiFunction<T,?U>- Represents a function that accepts two arguments and produces a double-valued result.
  • ToDoubleFunction<T>- Represents a function that produces a double-valued result.
  • ToIntBiFunction<T,?U>- Represents a function that accepts two arguments and produces an int-valued result.
  • ToIntFunction<T>- Represents a function that produces an int-valued result.
  • ToLongBiFunction<T,?U>- Represents a function that accepts two arguments and produces a long-valued result.
  • ToLongFunction<T>- Represents a function that produces a long-valued result.

Operator functional interfaces

Function functional interfaces may produce result of the same type as argument or different but there are Operator functional interfaces that always return the value of same type as the passed arguments. Base Operator functional interfaces extend their Function interface counterpart like UnaryOperator extends Function and BinaryOperator extends BiFunction.

  • BinaryOperator<T>- Represents an operation upon two operands of the same type, producing a result of the same type as the operands.
  • DoubleBinaryOperator- Represents an operation upon two double-valued operands and producing a double-valued result.
  • DoubleUnaryOperator- Represents an operation on a single double-valued operand that produces a double-valued result.
  • IntBinaryOperator- Represents an operation upon two int-valued operands and producing an int-valued result.
  • IntUnaryOperator- Represents an operation on a single int-valued operand that produces an int-valued result.
  • LongBinaryOperator- Represents an operation upon two long-valued operands and producing a long-valued result.
  • LongUnaryOperator- Represents an operation on a single long-valued operand that produces a long-valued result.
  • UnaryOperator<T>- Represents an operation on a single operand that produces a result of the same type as its operand.

Predicate Functional interface

java.util.function.Predicate<T> functional interface represents a boolean valued function returning either true or false. Abstract method in this functional interface is test(Object).

@FunctionalInterface
public interface Predicate<T> {
  boolean test(T t);
}

Here is a list of pre-defined Predicate functional interfaces sharing the same behavior of accepting argument(s) and producing a boolean result.

  1. BiPredicate<T,?U>- Represents a predicate (boolean-valued function) of two arguments.
  2. DoublePredicate- Represents a predicate (boolean-valued function) of one double-valued argument.
  3. IntPredicate- Represents a predicate (boolean-valued function) of one int-valued argument.
  4. LongPredicate- Represents a predicate (boolean-valued function) of one long-valued argument.

That's all for the topic Built-in Functional Interfaces in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

Functional Interface in Java

Functional interface in Java is an interface with a single abstract method. Here is a functional interface example in Java.

interface MyFunctionalInterface{
  void calculateInterest(int i);
}

This interface qualifies as a functional interface because there is a single unimplemented method in the interface.

What qualifies as a functional interface

Java 8 onward an interface can have default methods, static methods and Java 9 onward even private methods, so a functional interface can have these methods too but it should have only a single unimplemented method to be qualified as a functional interface.

If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method.

Following interface qualifies as a functional interface even though it contains a default method and a private method as it has a single abstract method.

@FunctionalInterface
interface MyFunctionalInterface{
  void calculateInterest(int i);	
  default void defMethod(){
    commonCode();
    System.out.println("In default method 2");
  }
  private  void commonCode(){
    System.out.println("Executing common code...");
  }
}

Functional interface and Lambda expression

Though there were already interfaces in Java with a single abstract method, like Runnable with its single run() method, Callable with its call() method or Comparator with its compare() method but the term "functional interface" came into fore with the introduction of Lambda expressions in Java 8.

Lambda expression on its own is just a function which needs a target type context to be executed. Since Java is an object oriented language so Lambda expression has to be wrapped with in an object that’s what functional interface provides. Lambda expression specifies the implementation of the abstract method defined by the functional interface and that's how functional interface provides target type for Lambda expression.

Let’s see an example where lambda expression is assigned to a functional interface reference.

//Functional interface
interface MyFunctionalInterface{
  void calculateSimpleInterest(int p, int r, int t);
}
public class LambdaExample {
  public static void main(String[] args) { 
    // lambda assigned to functional interface reference
    MyFunctionalInterface ref = (int p, int r, int t) -> System.out.println("Simple Interest is " + (p*r*t)/100);
    ref.calculateSimpleInterest(10000, 5, 3);
  }
}
Output
Simple Interest is 1500

In the example you can see that the Lambda expression is assigned to MyFunctionalInterface reference. Since target type for lambda expression here is MyFunctionalInterface so an instance of a class is automatically created that implements the functional interface and lambda expression provides implementation of the abstract method declared by the functional interface.

Here is an another example where lambda expression is passed as a method argument. In that case functional interface provides target type as a method parameter.

public class LambdaExample {
  public static void main(String[] args) { 
    new Thread(()->System.out.println("Method argument to Runnable")).start();
  }
}
Output
Method argument to Runnable

Above example is an implementation of Runnable as Lambda expression. As you can see here Thread constructor where Runnable is passed as method parameter is used and Lambda expression implementing the run() method of the Runnable functional interface is passed as method argument. Java run time is able to infer the target type from the context it is used.

@FunctionalInterface annotation in Java

@FunctionalInterface annotation is also added in Java 8 to be used with functional interfaces in Java. By annotating an interface with @FunctionalInterface annotation it is ensured that the interface won’t have more than one abstract method. It is advisable to use it with your functional interface so that no other abstract method is added to the interface even accidentally.

Here is an example of trying to add another abstract method to a functional interface annotated with @FunctionalInterface annotation.

@FunctionalInterface
interface MyFunctionalInterface{
  int calculateSimpleInterest(int p, int r, int t);
  void test(int i);
}

This functional interface gives compile time error “Invalid '@FunctionalInterface' annotation; MyFunctionalInterface is not a functional interface” as there are more than one abstract method.

Pre-packaged Functional interfaces in Java

In the examples shown above we have created our own functional interface but Java comes pre-packaged with many functional interface covering most of the scenarios. A whole new package java.util.function is added in Java 8 containing many functional interfaces to be used off the shelf.

Some of the inbuilt functional interfaces are as follows-

  1. BiConsumer<T,U>- Represents an operation that accepts two input arguments and returns no result.
  2. BiFunction<T,U,R>- Represents a function that accepts two arguments and produces a result.
  3. BinaryOperator<T>- Represents an operation upon two operands of the same type, producing a result of the same type as the operands.
  4. Function<T,R>- Represents a function that accepts one argument and produces a result.
  5. Predicate<T>- Represents a predicate (boolean-valued function) of one argument.
  6. Supplier<T>- Represents a supplier of results.
  7. UnaryOperator<T>- Represents an operation on a single operand that produces a result of the same type as its operand.

Check the whole list here- https://docs.oracle.com/javase/10/docs/api/java/util/function/package-summary.html

Example using BiFunction functional interface

Since BiFunction functional interface accepts two arguments and returns a result so it can be used where computation using two arguments is required.

public class LambdaExample {
  public static void main(String[] args) { 
    BiFunction<String, String, String> ref = (str1, str2) -> str1+ " " +str2;
    System.out.println("Concatenating Strings- " + ref.apply("Hello", "Lambda"));
  }
}
Output
Concatenating Strings- Hello Lambda

Example using Predicate functional interface

Predicate functional interface in Java has an abstract method test() which evaluates this predicate on the given argument and return true if the input argument matches the predicate, otherwise false.

Suppose you have a List of Integers and you want to get only those elements of the list which are greater than 10 then you can use Predicate functional interface to test if element is greater than 10 or not and return true only if it is greater than 10.

public class LambdaExample {
  public static void main(String[] args) { 
    List<Integer> myList = Arrays.asList(25, 5, 17, 1, 7, 14, 9, 11);
    LambdaExample obj = new LambdaExample();
    // Lambda expression as method arg
    List<Integer> filterdList = obj.filter(myList, (i) -> i>10);
    System.out.println("Filtered elements- " + filterdList);
  }
	
  public <T> List<T> filter(Collection<T> myList, Predicate<T> predicate) {
    List<T> filterdList = new ArrayList<T>();
    for(T element: myList) {
      if(predicate.test(element)) {
        filterdList.add(element);
      }
    }
    return filterdList;
  }
}
Output
Filtered elements- [25, 17, 14, 11]

In the example lambda expression (i) -> i>10 provides the implementation of the abstract method test() of the Predicate functional interface.

That's all for the topic Functional Interface in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like

Variable Scope in Java Lambda Expression

In this post we’ll see what is the scope of a variable with in a lambda expression in Java. This topic is important as it touches one of the concept that’s added in Java 8; Effectively final in Java.

Java lambda expression variable scope

Lambda expression in Java doesn’t have a scope of its own, it has the same scope as its enclosing scope. It results in an error if a variable is defined with in a lambda expression that has the same name as a variable in its enclosing scope.

For example-

String s1 = "Lambda";
// Error
Comparator<String> comp = (s1, s2) -> s1.length() - s2.length();

This lambda expression implements the compare() method of the Comparator functional interface but that will result in an error as the parameter used with in the lambda expression has the same name as the local variable s1 already defined. Thus this statement results in compile time error “Lambda expression's parameter s1 cannot redeclare another local variable defined in an enclosing scope”.

Accessing enclosing scope variable in Lambda expression

Since lambda expression does not introduce a new level of scoping you can directly access fields, methods, and local variables of the enclosing scope. However there is a restriction how variables from enclosing scope can be used. Like local and anonymous classes, a lambda expression can only access local variables and parameters of the enclosing scope that are final or effectively final.

An effectively final variable in Java is a variable whose value can't be modified once it is assigned. So any enclosing scope variable can either be declared as final or it is by default effectively final and it can’t be modified in lambda expression or in an inner class. Actually before Java 8 it was mandatory to define such a field (which is used in inner class) as final, Java 8 onward it is relaxed a bit and there is no need to explicitly declare such fields as final.

@FunctionalInterface
interface TestInterface{
  int calculate(int i, int j);
}
public class LambdaExample {
  public static void main(String[] args) { 
    int num = 7;
    TestInterface ref = (x, y) -> {
      // Modifying value of enclosing scope field
      num = x + y;
      return num;
    };
  }
}

In the above example with in the lambda expression block there is an attempt to modify the value of a variable from an enclosing scope that results in an error “Local variable num defined in an enclosing scope must be final or effectively final”.

Why effectively final

Now the question arises why such restriction for an enclosing scope variable. A lambda expression that uses the variables from the enclosing scope captures the values of such variables. Since lambda expression in Java is an instance of a functional interface so the fields of the enclosing scope used in such an instance captures the values of those fields and use it. It is important to maintain the state of such fields so that those are not modified that’s why this restriction of "effectively final".

Using this and super keyword in lambda expression

Since lambda expressions don’t introduce a new scope so using this keyword and super keyword with in a lambda refers to the same object that has invoked the method where the lambda expression resides.

@FunctionalInterface
interface TestInterface{
  int calculate(int i, int j);
}

class Test {
  public void showValue(String str) {
    System.out.println("Value is- " + str);
  }
}
public class LambdaExample extends Test{
  public static void main(String[] args) { 
    LambdaExample obj = new LambdaExample();
    obj.getResult();
  }
	
  public void getResult(){
    TestInterface ref = (x, y) -> {
      // Modifying value of enclosing scope field
      System.out.println("ToString- " + this.toString());
      super.showValue("Calling from Lambda");
      return x+y;
    };
    System.out.println("Result is- " + ref.calculate(8, 6));
  }
}
Output
ToString- com.knpcode.LambdaExample@66133adc
Value is- Calling from Lambda
Result is- 14

In the example, LambdaExample class extends class Test and has a method getResult() where we have a lambda expression. As you can see that lambda expression has access to the this and super. Calling this.toString() from the lambda prints an instance of LambdaExample not of TestInterface.

That's all for the topic Variable Scope in Java Lambda Expression. If something is missing or you have something to share about the topic please write a comment.


You may also like

Exception Handling With Java Lambda Expressions

In this post we’ll see exception handling with lambda expressions in Java. A lambda expression can throw an exception but that should be compatible with the exceptions specified in the throws clauses of the abstract method of the functional interface.

If a lambda expression body throws a checked exception, the throws clause of the functional interface method must declare the same exception type or its supertype.

Checked exception in lambda expression

In the example abstract method calculate of the functional interface MyFunctionalInterface doesn't have a throws clause but lambda body throws an exception. In such case a compiler error message "Unhandled exception type Exception" is generated.

Exception handling in lambda expression

If you specify the same exception in the functional interface method then the error is resolved but then you do need to handle it while calling the method.

@FunctionalInterface
interface MyFunctionalInterface{
  int calculate(int i, int j) throws Exception;
}
public class LambdaException {
  public static void main(String[] args) {
    MyFunctionalInterface ref = (x, y) -> {
      int num = x * y;
      throw new Exception();
      //return num;
    };
    try {
      System.out.println("Result is " + ref.calculate(8, 5));
    }catch(Exception e) {
      System.out.println("Exception while calculating " + e.getMessage());
    }
  }
}

Unchecked exception in lambda expression

In case of unchecked exception there is no such restriction that it should be specified in the abstract method of the functional interface.

In the example abstract method calculate of the functional interface MyFunctionalInterface doesn't have a throws clause but lambda body throws a runtime exception.

@FunctionalInterface
interface MyFunctionalInterface{
  int calculate(int i, int j);
}
public class LambdaException {
  public static void main(String[] args){
    MyFunctionalInterface ref = (x, y) -> {
      try {
        int num = x/y;
        return num;
      }catch(ArithmeticException e) {
        System.out.println("Exception while calculating- " + e.getMessage());
        throw new RuntimeException(e);
      }
    };

    System.out.println("Result is " + ref.calculate(8, 0));		
  }
}

Wrapping lambda to handle exceptions

Many people like to keep lambda expression code concise and clutter free with no try catch blocks.

In that case you can create a wrapper class wrapping your lambda and then calling it.

@FunctionalInterface
interface MyFunctionalInterface{
  int calculate(int i, int j);
}
public class LambdaException {
  // Lambda wrapper
  static MyFunctionalInterface lambdaWrapper(MyFunctionalInterface ref) {
    return (x, y) -> {
      try {
        ref.calculate(x, y);
      }catch(ArithmeticException e) {
        System.out.println("Exception while calculating- " + e.getMessage());
      }
      return -1;
    };
  }

  public static void main(String[] args){
    // calling lambda wrapp
    MyFunctionalInterface ref = lambdaWrapper((x,y)->x/y);
    System.out.println("Result is " + ref.calculate(8, 0));	
  }
}
Output
Exception while calculating- / by zero
Result is -1
Reference: https://www.oracle.com/technetwork/articles/java/lambda-1984522.html

That's all for the topic Exception Handling With Java Lambda Expressions. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Lambda Expressions With Examples

Java Lambda expression is one of the most important addition in Java 8. It is a step towards functional programming in Java programming language. This Java Lambda expression tutorial gives an overview of lambda expressions like what are lambda expressions, how to write one and what are the advantages of using lambda expressions.

Functional interface in Java

Before delving deep into lambda expressions you should know about the functional interfaces in Java.

A functional interface is an interface with only a single abstract method (SAM). There are already many functional interfaces in Java  (though many new ones added in Java 8) like Runnable with its single run() method, Callable with its call() method or Comparator with its compare() method.

To know more about Functional interfaces in Java please refer this post- Functional Interface in Java

Lambda expression in Java

Java lambda expression is an implementation of a functional interface. It is an instance of a functional interface and the lambda expression you write implements the abstract method of the functional interface.

Let’s try to clarify it with an example. Generally when you implement a functional interface most probably you will implement it as an anonymous class. For example if you have to implement a Comparator you will write it as an anonymous class as given below-

List<Integer> myList = Arrays.asList(4, 7, 1, 10, 8, 12);
Collections.sort(myList, new Comparator<Integer>() {
  @Override
  public int compare(Integer o1, Integer o2) {		
    return o2.compareTo(o1);
  }
});

Since Comparator is a functional interface it can also be implemented as a Lambda expression.

Collections.sort(myList, (Integer o1, Integer o2)-> o2.compareTo(o1));

Some important points you should notice here are-

  1. By implementing a functional interface as a lambda expression, code is more compact.
  2. If you see the Collections.sort() method what you have done is written a function- (Integer o1, Integer o2)->o2.compareTo(o1) that represents an instance of a functional interface and it can be passed as a method argument. That is one of the advantages of lambda expression you can pass functionality as an argument to another method.

Arrow operator or Lambda operator

Java lambda expressions introduce a new operator -> knows as Arrow operator in Java. Arrow operator has two parts-

Left side specifies parameters required by the lambda expression which can be empty too if there are no parameters.

Right side is the lambda body which is actually the code of your lambda expression.

So the syntax of Java Lambda expression is as follows-

(type arg1, type arg2, ....) -> lambda body

Type can be inferred from the context in which lambda expression is used so you don’t need to explicitly specify type of the parameters.

(arg1, arg2, ....) -> lambda body

If we consider the lambda expression we have already written-

Lambda expressions in Java examples

Now when you have a good idea of functional interface and how to write a lambda expression let’s see some more examples of Lambda expressions in Java.

1- The simplest lambda expression is one with no parameters and just a return value and it can be written as.

()-> 10;
The above lambda expression is put to use in the following class.
// Functional interface
interface TestInterface{
  int getValue();
}

public class LambdaExample {
  public static void main(String[] args) {
    // assigning to functional interface reference
    TestInterface ref = () -> 10;
    System.out.println("Value- " + ref.getValue());
  }
}
Output
Value- 10

Some important points you should notice here are-

  • Since lambda expression is an instance of functional interface so it can be referred using a functional interface reference as done in this statement- TestInterface ref = () -> 10;
  • Since there are no parameters so left side of the arrow operator is just empty parenthesis.

2- A lambda expression with parameters.

// Functional interface
interface TestInterface{
  String getValue(String str1, String str2);
}

public class LambdaExample {
  public static void main(String[] args) {
    // assigning to functional interface reference
    TestInterface ref = (String str1, String str2) -> str1 + " " + str2;
    System.out.println("Value- " + ref.getValue("Hello", "Lambda"));
  }
}
Output
Value- Hello Lambda

Here we have a lambda expression with two String parameters. You don’t need to specify types of the parameters as that can be inferred from the context it is used, so this is also acceptable-

TestInterface ref = (str1, str2) -> str1 + " " + str2;

Lambda expression as a method argument

In the beginning we have already seen an example where Comparator implementation as a lambda expression is passed as a method argument. This is one of the feature of the lambda expression; to treat functionality as method argument.

If you have a method where argument is a functional interface then you can pass a lambda expression compatible with that functional interface as a method parameter.

In the following Java lambda expression as method argument example there is a method invoke that has a Callable as argument. Since Callable is a functional interface so a lambda expression compatible to it is passed as a parameter while calling invoke method.

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class LambdaExample {
  public static void main(String[] args) {
    LambdaExample obj = new LambdaExample();
    try {
      Future<String> f  = obj.invoke(()->"Calling callable");
      System.out.println("Value returned from callable- " + f.get());
    }catch(Exception e) {
      System.out.println("Exception message- " + e.getMessage());
    }      
  }
    
  //Method with Callable(funtional interface) as parameter
  <T> Future<T> invoke(Callable<T> c) throws Exception {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<T> f =  executor.submit(c);
    executor.shutdown();
    return f;
  }
}
Output
Value returned from callable- Calling callable

Block lambda expressions in Java

What we have seen till now are all single expressions but you can also have lambda expressions having multiple statements known as block lambda expressions.

In a block lambda expression enclose the block of code with in curly braces and explicitly use return to return a value.

//Functional interface
interface TestInterface{
  String getValue(int i);
}

public class LambdaExample {
  public static void main(String[] args) {
    //block lambda
    TestInterface ref = (int i) -> {
      String s;
      if((i % 2) == 0) {
        s = "Even";
      }else {
        s = "Odd";
      }
      return s;
    };
    
    int num = 5;
    System.out.println(num + " is- " + ref.getValue(num));
  }
}
Output
5 is- Odd

That's all for the topic Java Lambda Expressions With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

Java Generics- Generic Class, Interface And Method

Generics in Java was introduced in Java 5 to provide strict type checking at compile time.

Type parameters in Java Generics

Generics in Java enables you to write generic classes, interfaces and methods that can work with different data types. It is possible because you specify type parameters when defining classes, interfaces and methods. Type parameter can be any class or interface like Integer, String, custom class or interface.

For example in Collection API ArrayList class is written as-

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{

..
..
}

Here E is a type parameter which is enclosed in angle brackets (<>). Since a type parameter is specified- ArrayList<E> that means ArrayList class is a generic class where E is the type of elements in this List. With this generic class definition ArrayList can work with different data types. You will have to specify the actual type while initializing the ArrayList.

//List that stores Integers
List<Integer> nList = new ArrayList<Integer>();
nList.add(1);
nList.add(2);
nList.add(3);

// List that stores Strings
List<String> sList = new ArrayList<String>();
sList.add("A");
sList.add("B");
sList.add("C");

// List that stores objects of type Employee
List<Employee> eList = new ArrayList<Employee>();
Employee emp1 = new Employee("Jean", "HR", 6000);
eList.add(emp1);

Why Generics is required

You may argue that there is already an Object class in Java that can be used to refer any class object making it a good candidate to be used as a generic parameter. For example in the following class there is a method that has Object type as a parameter so you can pass any type to this method.

public class Test {
  public static void main(String[] args) throws IOException {
    Test t = new Test();
    t.display(1);
    t.display("Hello");
    t.display(5.67);
  }

  public void display(Object o) {
    System.out.println("passed argument is- " + o);
    System.out.println("passed argument's type is- " + o.getClass().getTypeName());
  }
}
Output
passed argument is- 1
passed argument's type is- java.lang.Integer
passed argument is- Hello
passed argument's type is- java.lang.String
passed argument is- 5.67
passed argument's type is- java.lang.Double

As you can see by using Object as parameter I can have a generic method that can work with any type so why Generics is required. Answer is Generics in Java bring type safety to your code. We’ll discuss that feature in next section.

Benefits of Java Generics

1. Strict type checks at compile time

Generics provide strict type checks at compile time so any type violation will give error as compile time itself rather than java.lang.ClassCastException thrown at run time.

For example you have initialized a List as a non-generic List and your intention is to store strings in it. Since it is not Generic which means all its elements will be stored as objects of Object class. If you add an Integer to this List by mistake there won't be any compile time error as Integer is also of type Object.

At the time of retrieving element from the List you will have to explicitly cast it to the type and that time it will throw ClassCastException when it encounters Integer.

public class Test {
  public static void main(String[] args) throws IOException {
    // Not generic
    List sList = new ArrayList();
    sList.add("A");
    sList.add("B");
    // Adding Integer
    sList.add(1);
    sList.add("C");
    
    Iterator itr = sList.iterator();
    while(itr.hasNext()){
      // Casting to string when retrieving
      String str = (String)itr.next();
      System.out.println("" + str);
    }
  }
}
Output
A
B
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
	at com.knpcode.programs.Test.main(Test.java:27)

With Generics you can specify the type of elements that can be stored in the List thus providing type safety. If you try to add element of any other type to this List you will get error at compile time itself.

public class Test {
  public static void main(String[] args) throws IOException {
    // Generic List
    List<String> sList = new ArrayList<String>();
    sList.add("A");
    sList.add("B");
    // Not allowed, Error at compile time if 
    // Integer is added 
    //sList.add(1);
    sList.add("C");
    
    Iterator<String> itr = sList.iterator();
    while(itr.hasNext()){
      String str = itr.next();
      System.out.println("" + str);
    }
  }
}

2. Explicit casting not required

Since type is specified with Generics and it is ensured that you can store elements only of the specified type so explicit casting is not required when retrieving elements.

In the above code when using a non-generic List, type casting is required.

Iterator itr = sList.iterator();
while(itr.hasNext()){
  // Casting to string when retrieving
  String str = (String)itr.next();
  System.out.println("" + str);
}

With a generic List type casting is not required.

Iterator<String> itr = sList.iterator();
while(itr.hasNext()){
  String str = itr.next();
  System.out.println("" + str);
}

3. Implement generic algorithms

By using generics, programmers can implement generic algorithms that work on different types, easier to read and are type safe too. Here is a simple Generic class example that can set and get value of any type.

public class Test<T> {
  T obj;
  public T getObj() {
    return obj;
  }
  public void setObj(T obj) {
    this.obj = obj;
  } 

  public static void main(String[] args) throws IOException {
    // With Integer type
    Test<Integer> intParam = new Test<Integer>();
    intParam.setObj(7);
    int value = intParam.getObj();
    System.out.println("Integer value- " + value);
    
    // With String type
    Test<String> strParam = new Test<String>();
    strParam.setObj("Test Value");
    String str = strParam.getObj();
    System.out.println("String value- " + str);
    
    // With Double type
    Test<Double> doubleParam = new Test<Double>();
    doubleParam.setObj(23.45);
    double dblValue = doubleParam.getObj();
    System.out.println("Double value- " + dblValue);
  }
}
Integer value- 7
String value- Test Value
Double value- 23.45

See How to write a generic Bubble Sort in Java in this post- Generic Bubble Sort Java Program

Type Parameter Naming Conventions in Java Generics

By convention, type parameter names are single, uppercase letters. The most commonly used type parameter names are:

  • T - Type
  • V - Value
  • E - Element
  • K - Key
  • N - Number
  • S,U,V etc. - 2nd, 3rd, 4th types

Generic Class

With the introduction of Generics done let’s see how we can create a Generic class in Java.

A generic class is defined with the following format:

class name<T1, T2, ..., Tn> { /* ... */ }

After the class name there is a type parameter section, delimited by angle brackets (<>). It specifies the type parameters (also called type variables) T1, T2, ..., and Tn.

Generic class creation Java example

In this example we'll create a generic class with two type parameters and use it with different data types.

class GenericClass<K, V> {
  private K key;
  private V value;
  public GenericClass(K key, V value) {
    this.key = key;
    this.value = value;
  }
  public K getKey(){
    return key;
  }
  public V getValue(){
    return value;
  }
}

public class GenericDemo{
  public static void main(String[] args) {
    GenericClass<String, String> g1 = new GenericClass<>("Test", "Value");
    System.out.println("Key- " + g1.getKey());
    System.out.println("Value- " + g1.getValue());

    GenericClass<Integer, Integer> g2 = new GenericClass<>(1, 2);
    System.out.println("Key- " + g2.getKey());
    System.out.println("Value- " + g2.getValue());
    
    GenericClass<Integer, String> g3 = new GenericClass<>(1, "One");
    System.out.println("Key- " + g3.getKey());
    System.out.println("Value- " + g3.getValue());
  }    
}
Output
Key- Test
Value- Value
Key- 1
Value- 2
Key- 1
Value- One

Generic Interface

A Generic interface is created just like Generic class.

interface name<T1, T2, ..., Tn> { /* ... */ }

Some of the rules that are to be followed while implementing a Generic Interface are as given below

  1. If generic type parameter is used with the interface then the class that implements a generic interface has to be a generic class with the same type parameter.
    public class GenericClass<E> implements GenericInterface<E>
    
  2. If you provide a data type with the Interface then you can use a normal class.
    public class NormalClass implements GenericInterface<Integer>
    
  3. A Generic class can have other parameters too apart from the type parameter it has to use because if implementing a generic interface.
    public class GenericClass<K, V, E> implements GenericInterface<E>
    

Generic Method

Any method in Generic class can specify the type parameters of the class and free to add type parameters of its own too. You can have a generic method in a non-generic class too.

Generic Method Java example

Here we’ll have a generic method in a non-generic class.

class TestClass {
  // Generic method
  public <T> void displayArrayElements(T[] arr){
    System.out.println("Elements in Array- " + Arrays.toString(arr));
  }
}

public class GenericDemo{
  public static void main(String[] args) {
    TestClass obj = new TestClass();
    Integer[] intArray = {1, 2, 3, 4, 5, 6, 7};
    Double[] doubleArray = {1.2, 2.3, 3.4, 4.5, 5.6};
    String[] strArray = {"A", "B", "C", "D"};
    obj.displayArrayElements(intArray);
    obj.displayArrayElements(doubleArray);
    obj.displayArrayElements(strArray);
  }    
}
Output
Elements in Array- [1, 2, 3, 4, 5, 6, 7]
Elements in Array- [1.2, 2.3, 3.4, 4.5, 5.6]
Elements in Array- [A, B, C, D]

As you can see if you are writing a generic method with its own type parameters then you need to declare type parameters after the access modifier.

public <T> void displayArrayElements(T[] arr)

You can also specify the actual data type in angular brackets when calling a generic method. Though Java can automatically infer type based on the type of the method arguments so doing that is not mandatory.

obj.displayArrayElements(intArray);
Or this
obj.<Integer>displayArrayElements(intArray);

The Diamond Operator

Java 7 onward it is not mandatory to specify the type arguments required to invoke the constructor of a generic class, you can pass an empty set of type arguments (<>) as long as the compiler can determine, or infer, the type arguments from the context. This pair of angle brackets, <>, is informally called the diamond.

For example, If you have a Generic class defined as given below

public class Test<T> {
    ..
    ..
}

Then you can create its instance like this Java 7 onward.

Test<Integer> obj = new Test<>();

No need to specify Integer on the right hand side, just pass the empty angle brackets <>, type will be inferred automatically.

That's all for the topic Java Generics- Generic Class, Interface And Method. If something is missing or you have something to share about the topic please write a comment.


You may also like

How to Create Temporary File in Java

Sometimes in your Java application you may want to store some data in a temporary file that can safely be deleted when the work is done. Java IO and NIO APIs itself provide methods to create a temporary file in Java.

Methods in java.io.File class to create temporary file

In java.io.File class there are two methods:

  • createTempFile(String prefix, String suffix)- Creates an empty file in the default temporary-file directory, using the given prefix and suffix to generate its name.
  • createTempFile(String prefix, String suffix, File directory)- Creates a temp file in the specified directory, using the given prefix and suffix strings to generate its name. Specified directory should be an existing directory

Temporary file creation Java example using java.io.File class methods

import java.io.File;
import java.io.IOException;

public class TempFileCreation {
  public static void main(String[] args) {
    try {
      // Using default temp directory
      File tempFile = File.createTempFile("TempFile", ".temp");
      System.out.println("Temporary file path (Default)- " + tempFile.getCanonicalPath());
      // Specifying directory
      File testFile = File.createTempFile("TempFile", ".temp", new File("F:\\knpcode"));
      System.out.println("Temporary file path- " + testFile.getCanonicalPath());
      // Work with temp file (IO Operations)
      // Delete on exit
      tempFile.deleteOnExit();
      testFile.deleteOnExit();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 
  }
}
Output
Temporary file path (Default)- C:\Users\knpcode\AppData\Local\Temp\TempFile8121084790462887465.temp
Temporary file path- F:\knpcode\TempFile7094477988758089030.temp

Note that deleteOnExit() method is used to delete the file when the virtual machine terminates.

Methods in java.nio.file.Files class to create temporary file

In java.nio.file.Files class there are two methods:

  • createTempFile(String prefix, String suffix, FileAttribute<?>... attrs)- Creates temp file in the default temporary-file directory, using the given prefix and suffix to generate its name.
  • createTempFile(Path dir, String prefix, String suffix, FileAttribute<?>... attrs)- Creates temp file in the specified directory, using the given prefix and suffix strings to generate its name.

Temporary file creation Java example using java.nio.file.Files class methods

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class TempFileCreation {
  public static void main(String[] args) {
    try {
      // Using default directory
      Path tempFile = Files.createTempFile("TempFile", ".temp");
      System.out.println("Temporary file path (Default)- " + tempFile);
      // Specifying directory
      Path testFile = Files.createTempFile(Path.of("F:\\knpcode"), "TempFile", ".temp");
      System.out.println("Temporary file path- " + testFile);
      // Work with temp file (IO Operations)
      // Delete on exit  
      tempFile.toFile().deleteOnExit();
      testFile.toFile().deleteOnExit();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } 
  }
}
Output
Temporary file path (Default)- C:\Users\knpcode\AppData\Local\Temp\TempFile14952623994848508190.temp
Temporary file path- F:\knpcode\TempFile10342615863071845696.temp

That's all for the topic How to Create Temporary File in Java. If something is missing or you have something to share about the topic please write a comment.


You may also like