Showing posts with label Java 8. Show all posts
Showing posts with label Java 8. Show all posts

Friday, May 17, 2024

@FunctionalInterface Annotation in Java

In the post Functional Interfaces in Java we have already seen that functional interfaces are those interfaces that have only one abstract method. Java 8 also introduced an annotation @FunctionalInterface to be used with functional interfaces. Annotating an interface with @FunctionalInterface in Java indicates that an interface type declaration is intended to be a functional interface.

It is not mandatory to mark functional interface with @FunctionalInterface annotation, it is more of a best practice to do that and also gives a surety that no other abstract method will be added accidentally to the functional interface. It will result in a compile time error if any other abstract method is added to a functional interface which is annotated with @FunctionalInterface annotation.

Let's see it with some examples what is permitted and what is not with @FunctionalInterface annotation in Java.
First there is an example of a valid functional interface that is annotated with @FunctionalInterface-

 
@FunctionalInterface
public interface IMyFuncInterface {
  public void getValue();
}

In an interface annotated with @FunctionalInterface, if more than one abstract method is defined it results in compile time error.

@FunctionalInterface
public interface IMyFuncInterface {
  public void getValue();
  // Second abstract method so compiler error
  public void setValue();
}

Note that in Java 8 default methods and static methods are also added in interface which means interface can have a method with default implementation and static methods in Java 8. In a functional interface there may be one or more default methods/static methods but there should be only one abstract method. It is ok to have a functional interface like following.

 
@FunctionalInterface
public interface IMyFuncInterface {
  int func(int num1, int num2);
  // default method
  default int getValue(){
    return 0;
  }    
}

A functional interface can specify Object class public methods too in addition to the abstract method. That interface will still be a valid functional interface. The public Object methods are considered implicit members of a functional interface as they are automatically implemented by an instance of functional interface.

As example- This is a valid functional interface

@FunctionalInterface
interface IFuncInt {
  int func(int num1, int num2);
  // default method
  default int getValue(){
    return 0;
  }
  public String toString();
  public boolean equals(Object o);
}

That's all for this topic @FunctionalInterface Annotation in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Lambda Expressions in Java 8
  2. How to Fix The Target Type of This Expression Must be a Functional Interface Error
  3. Method Reference in Java 8
  4. Java Lambda Expression as Method Parameter
  5. Java Lambda Expressions Interview Questions And Answers

You may also like-

  1. Fail-Fast Vs Fail-Safe Iterator in Java
  2. How to Iterate a HashMap of ArrayLists of String in Java
  3. strictfp in Java
  4. static Import in Java With Examples
  5. Synchronization in Java - Synchronized Method And Block
  6. Deadlock in Java Multi-Threading
  7. Difference Between Checked And Unchecked Exceptions in Java
  8. Externalizable Interface in Java

Thursday, April 18, 2024

Functional Interfaces in Java

A functional interface in Java is an interface with only one abstract method. A functional interface is also known as SAM type where SAM stands for (Single Abstract Method). An example of functional interface with in Java would be Runnable interface which has only one method run().


Java functional interface example

interface IMyInterface {
  int getValue();
}

In interface IMyInterface there is only single abstract method getValue() (note that in an interface methods are implicitly abstract).

Wednesday, April 3, 2024

Java Stream API Tutorial

If we have to point out the most important inclusion in Java 8 apart from lambda expressions then that has to be Stream API in Java. Stream API usually works in conjunction with lambda expression and provide an easy yet efficient way to perform data manipulation operations like sort, filter, map, reduce etc.

This Javs Stream API tutorial gives an overview of what exactly is a stream in Stream API and what all types of Stream operations are there.


What is Stream in Java Stream API

A stream can be visualized as a pipeline. A stream pipeline consists of a source (which might be an array, a collection, a generator function, an I/O channel, etc), zero or more intermediate operations (which transform a stream into another stream, such as filter(Predicate)), and a terminal operation (which produces a result or side-effect, such as count() or forEach(Consumer)).

Stream API in Java
Stream data flow

Monday, March 25, 2024

Java Stream API Examples

In the post Java Stream API Tutorial we have already got an introduction of Stream API. A Stream can be defined as a sequence of elements supporting sequential and parallel aggregate operations. Using these aggregation operations we can create a pipeline. Some of the aggregation operations provided are collect, concat, count, distinct, filter, forEach, limit, map, max, min, reduce, sorted. In this post we’ll see some Java stream API examples using these operations and also create pipeline consisting sequence of aggregate operations.


Java Stream API count() method example

count method returns the count of elements in the given stream.

Note that this is a special case of a reduction and it is a terminal operation.

List<Integer> myList = Arrays.asList(7, 18, 10, 24, 17, 5);  
long count = myList.stream().count();
System.out.println("Total elements in the list " + count);

This code snippet will give the count of the elements in the List.

Now if you want to get the count of the elements greater than 10 you can create a pipeline where you first filter on the predicate that you want those elements of the list whose value is greater than 10 and then count those elements.

List<Integer> myList = Arrays.asList(7, 18, 10, 24, 17, 5); 
long count = myList.stream().filter(i -> i > 10).count();
System.out.println("Total elements in the list with value greater than 10 " + count);

Java Stream API concat() method example

concat() method in Java Stream creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream.

List<String> myList = Arrays.asList("1", "2", "3", "4", "5");
  
String[] arr1 = { "a", "b", "c", "d" };
// concatenating two streams
Stream<String> stream = Stream.concat(myList.stream(), Arrays.stream(arr1));
stream.forEach(System.out::print);

Output

12345abcd

Here you can see the concatenated stream is returned. If you are wondering what is this System.out::print refer Method reference in Java 8. You may also want to read about forEach statement in Java 8.

Since parameters of the concat operations are streams so all the aggregation operations can be applied to them too. As example if there are two lists having name and you want a merged list with all the names that start with “A” that can be done as follows–

List<String> nameList1 = Arrays.asList("Ram", "Amit", "Ashok", "Manish", "Rajat");
  
List<String> nameList2 = Arrays.asList("Anthony", "Samir", "Akash", "Uttam");
  
String[] arr1 = { "a", "b", "c", "d" };
// concatenating two streams
Stream<String> stream = Stream.concat(nameList1.stream().filter(n -> n.startsWith("A")), nameList2.stream().filter(n -> n.startsWith("A")));

stream.forEach(System.out::println);

Java Stream API distinct() method example

Returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.

Using distinct method of the Java Stream API, duplicate elements from a collection like list can be removed very easily by creating a pipeline where distinct method will return a stream having distinct elements only which can later be collected in a list using collect method.

List<Integer> myList = Arrays.asList(7, 18, 10, 7, 10, 24, 17, 5);
  
System.out.println("Original list: " + myList);
List<Integer> newList = myList.stream().distinct().collect(Collectors.toList());

System.out.println("new List : " + newList);

Java Stream API filter() method example

filter method returns a stream consisting of the elements of this stream that match the given predicate.

Here note that Predicate is a functional interface and can be implemented as a lambda expression. In the above examples we have already used filter method.

As an example let’s say we have a list of names and we want to print names which doesn’t start with “A”.

List<String> nameList = Arrays.asList("Ram", "Amit", "Ashok", "Manish", "Rajat");
  
nameList.stream().filter(n -> !n.startsWith("A")).collect(Collectors.toList()).forEach(System.out::println);

Output

Ram
Manish
Rajat

Java Stream API limit() method example

Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.

If you want 10 random numbers, then you can use limit method with the int stream.

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

Java Stream API map() method example

Returns a stream consisting of the results of applying the given function to the elements of this stream. So, whatever function is provided is applied on all the elements of the stream. Note that this is an intermediate operation.

As Example– If you have a list of salaries and you want to increase it by 10%.

List<Integer> myList = Arrays.asList(7000, 5000, 4000, 24000, 17000, 6000);
  
myList.stream().map(i -> (i+ i * 10/100)).forEach(System.out::println);

findFirst() and findAny() methods in Java Stream API

  • findFirst()- Returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty. If the stream has no encounter order (List or Array wil be ordered, where as set or map won’t), then any element may be returned.
  • findAny()- Returns an Optional describing some element of the stream, or an empty Optional if the stream is empty. The behavior of this operation is explicitly nondeterministic; it is free to select any element in the stream. This is to allow for maximal performance in parallel operations; the cost is that multiple invocations on the same source may not return the same result. (If a stable result is desired, use findFirst() instead.)
List<String> nameList = Stream.of("amy", "nick", "margo", "desi");
Optional<String> name = nameList.stream().findFirst();
System.out.println("First Name " + name);

name = nameList.parallelStream().findAny();
System.out.println("First Name " + name);

Output

First Name Optional[amy]
First Name Optional[margo]

You can see in case of findFirst() method, first element of the list is displayed. Even with parallelStream, findFirst() will give the first element.

Whereas in case of findAny() method any random element is picked. You can see that findAny() method is used with parallelStream here.

max and min methods in Java Stream API

  • max- Returns the maximum element of this stream according to the provided Comparator.
  • min- Returns the minimum element of this stream according to the provided Comparator.

max and min are also reduction operations. Both of them are terminal operations.

List<Integer> myList = Arrays.asList(7000, 5000, 4000, 24000, 17000, 6000);
// Obtain a Stream to the array list.
Stream<Integer> myStream = myList.stream();
Optional<Integer> val = myStream.min(Integer::compare);
if(val.isPresent()){
 System.out.println("minimum value in the list " + val.get());
}  
Optional<Integer> val1 = myList.stream().max(Integer::compare);
if(val1.isPresent()){
 System.out.println("maximum value in the list " + val1.get());
}

Note that here Optional class is used. To know more about Optional class refer Optional class in Java 8.

Java Stream API sorted() method example

sorted method returns a stream consisting of the elements of this stream, sorted according to natural order or there is another variant where custom comparator can be provided.

List<Integer> myList = Arrays.asList(7000, 5000, 4000, 24000, 17000, 6000);
myList.stream().sorted().forEach(System.out::println);

Summary Statistics classes

A state object for collecting statistics such as count, min, max, sum, and average. There are different SummaryStatistics classes in Java Stream API like IntSummaryStatistics, DoubleSummaryStatistics, LongSummaryStatistics.

As example–

 
List<Integer> myList = Arrays.asList(7, 5, 4, 24, 17, 6);
IntSummaryStatistics stats = myList.stream().collect(Collectors.summarizingInt(i-> i));

System.out.println("Sum - " + stats.getSum());
System.out.println("Count " + stats.getCount());
System.out.println("Average " + stats.getAverage());
System.out.println("Max " + stats.getMax());
System.out.println("Min " + stats.getMin());

Here Collectors.summarizingInt method is used which applies an int-producing mapping function to each input element, and returns summary statistics for the resulting values.

In place of

IntSummaryStatistics stats = myList.stream().collect(Collectors.summarizingInt(i-> i));

Using mapToInt method it can also be written as -

IntSummaryStatistics stats = myList.stream().mapToInt(i -> i).summaryStatistics();

That's all for this topic Java Stream API Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Parallel Stream in Java Stream API
  2. Primitive Type Streams in Java Stream API
  3. Reduction Operations in Java Stream API
  4. Lambda Expressions in Java 8
  5. Java Stream API Interview Questions And Answers

You may also like-

  1. How HashMap Works Internally in Java
  2. How ArrayList Works Internally in Java
  3. Java ReentrantLock With Examples
  4. Difference Between ArrayList And CopyOnWriteArrayList in Java
  5. Lock Striping in Java Concurrency
  6. Java ThreadLocal Class With Examples
  7. Spring NamedParameterJdbcTemplate Insert, Update And Delete Example
  8. How to Inject Prototype Scoped Bean into a Singleton Bean in Spring

Wednesday, March 20, 2024

Java Stream - filter() With Examples

In this tutorial you will see some examples of filter() method in Java Stream API. filter() method is used to filter out some elements based on the passed condition and the remaining elements, that satisfy the condition, are returned as a new Stream.


filter() in Java

filter() in Java stream is an intermediate operation and its syntax is as given below-

Stream<T> filter(Predicate<? super T> predicate)

Here Predicate, which is a functional interface, is used to pass the condition that is used to filter out elements. Since Predicate is a functional interface so it is usually implemented as a lambda expression.

Wednesday, March 6, 2024

Java Stream - distinct() With Examples

In this tutorial you will see some examples of distinct() method in Java Stream API. Stream.distinct() method is used to remove duplicate elements and the method returns a new stream consisting of the distinct elements. To determine which elements are duplicates distinct() method uses the equals() method of the Object class.

distinct() in Java Stream

Syntax of the distinct() method is as given below-

Stream<T> distinct()

Here are some important points about the distinct operation.

  1. It is a stateful intermediate operation which means it may incorporate state from previously seen elements when processing new elements.
  2. Method takes no arguments and returns a new Stream consisting of the distinct elements.
  3. For ordered streams, distinct operation is stable i.e. if there are duplicate elements the element appearing first in the encounter order is preserved.
  4. For unordered streams there are no stability guarantees.

Tuesday, March 5, 2024

Java Stream - limit() With Examples

In Java Stream API limit(long maxSize) method is used to truncate the stream so that it is not longer than maxSize in length and the method returns a stream consisting of that many elements of this stream.

Java Stream limit() method

Syntax of the limit method is as given below-

Stream<T> limit(long maxSize)

Here maxSize argument represents the number of elements the stream should be limited to.

If maxSize is negative then IllegalArgumentException is thrown otherwise a new Stream is returned which is no longer than maxSize in length.

Notes about limit() method

  • limit() is generally considered a cheap operation on sequential stream pipelines
  • limit() can be quite expensive on ordered parallel pipelines, since limit(n) is constrained to return not just any n elements, but the first n elements in the encounter order.
  • It is a short-circuiting stateful intermediate operation. Since limit() method returns a new stream that makes it a stateful intermediate operation. An intermediate operation is short-circuiting if, when presented with infinite input, it may produce a finite stream as a result.

limit() Java examples

1. Getting a sublist from a List by limiting the number of elements to the first n elements of the original list.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamLimit {
  public static void main(String[] args) {
    StreamLimit sl = new StreamLimit();
    List<Integer> numList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    List<Integer> subList = numList.stream().limit(5).collect(Collectors.toList());     
    System.out.println("Sublist after limiting elements- " + subList);
  }
}

Output

Sublist after limiting elements- [1, 2, 3, 4, 5]

2. Getting 10 random numbers by using limit() with generate() method.

public class StreamLimit {
  public static void main(String[] args) {
    Stream.generate(Math::random)
          .map(n -> (int)(n * 100))
          .limit(10)
          .forEach(System.out::println);
  }
}

That's all for this topic Java Stream - limit() With Examples. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Java Stream - skip() With Examples
  2. Java Stream - distinct() With Examples
  3. Java Stream - max() With Examples
  4. Primitive Type Streams in Java Stream API
  5. Java Stream API Interview Questions And Answers

You may also like-

  1. Just In Time Compiler (JIT) in Java
  2. Byte Streams in Java IO
  3. How to Get The Inserted ID (Generated ID) in JDBC
  4. Method Reference in Java
  5. java.lang.ClassCastException - Resolving ClassCastException in Java
  6. Creating PDF in Java Using Apache PDFBox
  7. Method Overloading in Python
  8. Spring Boot Spring Initializr

Thursday, June 15, 2023

Lambda Expressions in Java 8

Lambda expressions in Java (also known as closures) are one of the most important feature added in Java 8. Java lambda expressions provide a clear and elegant way to represent a single abstract method interface (Functional interface) using an expression.


What is a functional interface

In order to know Lambda expressions better it is very important to have a good understanding of two terms- lambda expression itself and functional interface. Here is a little primer about functional interfaces.

A functional interface is an interface with only one abstract method. A functional interface is also known as SAM type where SAM stands for (Single Abstract Method). An example of functional interface would be Runnable interface which has only one method run().

Please note that from Java 8 it is possible for an interface to have default methods and static methods thus the stress on "only one abstract method".

Also a new annotation @FunctionalInterface has been added in Java 8, all the functional interfaces can be annotated with this annotation to ensure that they have only single abstract method.

functional interface Example

interface IMyInterface {
  int getValue();
}

In interface IMyInterface there is a single abstract method getValue() (note that in an interface methods are implicitly abstract).

See Functional Interfaces in Java for detailed post about functional interfaces.

Java lambda expressions

Lambda expression in Java is an instance of a functional interface and provides implementation of the single abstract method defined by the functional interface.

Lambda Expression Syntax

A new operator has been introduced in Java for Lambda expressions.

(arg1, arg2, ..) -> body

Here you can see a new arrow operator (->) or lambda operator which divides the lambda expression into two parts.

Left side specifies parameters required by the lambda expression. Parameters are optional, if no parameters are needed an empty parenthesis can be given. Even type of the parameters is not required as compiler, in most of the cases, is able to infer type of the parameters from the context in which it is used.

Right side known as lambda body specifies the logic of the lambda expression.

Why Lambda expressions in Java

Now when we have an idea about lambda expressions and functional interfaces let's try to understand how does lambda expressions help in making your code more compact.

Most used use case for anonymous class is to implement an interface that contains only one method. This is usually done when you are trying to pass functionality as an argument to another method.

For example if you have a List of objects of type Person and you want to sort them on the basis of first name using a Comparator. In that case you need to implement compare() method of the Comparator interface. Usually that is done by implementing Comparator as an anonnymous class. So what you are doing is to pass the functionality to compare objects as an argument to Collections.sort() method.

Collections.sort(personList, new Comparator<Person>() {
  public int compare(Person a, Person b) {
    return a.getFirstName().compareTo(b.getFirstName());
  }
});
Java lambda expression also enables you to do the same thing like-
  • Passing functionality as method argument.
  • Passing code as data.

Lambda expressions can only be used to implement functional interfaces (interface with single abstract method) and lambda expressions let you express these instances of single-method classes more compactly than by using anonymous class.

For example if you have to implement the same Comparator as used above as a lambda expression then it can be done more compactly as-

Collections.sort(personList, (Person a, Person b) -> 
            a.getFirstName().compareTo(b.getFirstName()));
Type can be inferred from the surrounding context so you don't even need to define the type of the parameters.
Collections.sort(personList, (a, b) -> 
            a.getFirstName().compareTo(b.getFirstName()));

Here you can see that the functionality for sorting (implementation of compare method of the Comparator) is passed as method argument.

Java lambda expression examples

Let's see some examples of the lambda expressions in Java-

1. A very simple lambda expression.

() -> 7; 

This lambda expression takes no parameter, that's why empty parenthesis and returns the constant value 7.

If we have to write the equivalent Java method then it will be something like this-

int getValue(){
  return 7;
}

2. Lambda expressions with 2 parameters.

// concatenating two strings, it has 2 string parameters
// and they are concatenated in lambda body
(String s1, String s2) -> s1+s2;

3. Lambda expression to test if the given number is odd or not.

// Lambda expression to test if the given number is odd or not
n -> n % 2 != 0;

4. Lambda expression to display passed argument.

// Prints the passed string s to the console and returns void
(String s) -> { System.out.println(s); };

5. Complete Java Lambda expression example.

interface IMyInterface {
  int getValue();
}

public class LambdaExpressionDemo {
  public static void main(String[] args) {
    // reference of the interface
    IMyInterface objRef;
    // Lambda expression
    objRef = () -> 7;
    System.out.println("Value is " + objRef.getValue());
    // Another lambda expression using the same interface reference 
    objRef = () -> 7 * 5;
    System.out.println("Value is " + objRef.getValue());
    // This line will give compiler error as target type 
    // can't be inferred 
    objref = () -> "11";
  }
}

Output

Value is 7
Value is 35

Here we have an interface IMyInterface with one method getValue() whose return type is int. Since there is only one abstract method in the interface so IMyInterface is a functional interface.

In this program it can be seen how lambda expression () -> 7 is compatible with the abstract method. Return type is int and there is no method parameter.
If you uncomment the line () -> "11"; it will give compiler error The target type of this expression must be a functional interface as in this case return type is string which is not compatible with the return type of the abstract method, lambda expression is implementing.

Also notice that the same functional interface reference is used to execute 2 lambda expressions
objRef = () -> 7; and objRef = () -> 7 * 5;
Since both of the lambda expressions are compatible with the target type so both of them can be assigned to the same reference (Does it remind you of run time polymorphism?). That's why Lambda Expression is a Poly Expression.

6. Java Lambda expression with a parameter example.

interface IMyInterface {
  boolean test(int n);
}

public class LambdaExpressionDemo {
  public static void main(String[] args) {
    IMyInterface objRef;
    // Lambda expression
    objRef = n -> (n % 2) == 0;
    System.out.println("4 is even " + objRef.test(4)); 
    System.out.println("3 is even " + objRef.test(3)); 
  }
}

Output

4 is even true
3 is even false

Here we need to note certain points-

n -> (n % 2) == 0;

In this lambda expression type is not specified explicitly as int, type is inferred from the context in which the lambda expression is executed, though type can be given explicitly too.

int n -> (n % 2) == 0;

This lambda expression is also valid.

Also parenthesis around the parameter is omitted, in case of single parameter it is not necessary to enclose the parameter with parenthesis. Again it won't be invalid to do that, so (n) -> (n % 2) == 0; or (int n) -> (n % 2) == 0; both are valid.

In case of more than one parameter too type can be inferred so
(int x, int y) -> x+y; or (x, y) -> x + y;
both of these are valid if used in a correct context.

One important point here is we can't have lambda expression where type for only one of the parameter is explicitly declared.

// Invalid lambda expression
(int x, y) -> x + y; 

See Lambda Expression Examples in Java for more examples of lambda expression.

Target type of Lambda expressions in Java

Lambda expression is an instance of the functional interface thus the functional interface specifies its target type.

Lambda supports "target typing" which infers the object type from the context in which it is used. To infer that object type from the context-

  • The parameter type of the abstract method and the parameter type of the lambda expression must be compatible. For Example, if the abstract method in the functional interface specifies one int parameter, then the lambda should also have one int parameter explicitly defined or implicitly inferred as int by the context.
  • Its return type must be compatible with the method's type.
  • Lambda expression can throw only those exceptions which are acceptable to the method.

Target typing is used in a number of contexts including the following-

  • Variable declarations
  • Assignments
  • Return statements
  • Array initializers
  • Method or constructor arguments
  • Lambda expression bodies

Block lambda expression in Java

Till now all the examples we have seen are single expression lambda, we also have a second type of lambda expressions known as "block lambda" where the right side of the lambda expression is a block of code.

Let's see an example, here with in the lambda expression we have a block of code for counting the words in a string without using any String function.

@FunctionalInterface
interface IMyInterface {
  int doCount(String str);
}

public class LambdaExpressionDemo {
  public static void main(String[] args) {
    // Lambda expression
    IMyInterface objRef = (str) -> {
      int c = 0;
      char ch[]= new char[str.length()];
      for(int i = 0; i < str.length(); i++){
          ch[i] = str.charAt(i);
          if(((i > 0) && (ch[i] != ' ') && (ch[i-1] == ' ')) || 
          ((ch[0] != ' ') && (i == 0)))
              c++;
      }
      return c;
    };    
    System.out.println("Words in the string " + objRef.doCount("Lambda Expression in Java"));    
  }
}

Output

Words in the string 4

Note here that functional interface is annotated with a @FunctionalInterface annotation, this is a new annotation added in Java 8 to be used with functional interface.

See Functional interface annotation in Java 8 for detailed post about @FunctionalInterface annotation.

Points to note-

  • Lambda expression is an instance of a functional interface and provides implementation of the single abstract method defined by the functional interface.
  • The lambda expression signature must be the same as the functional interface method's signature, as the target type of the lambda expression is inferred from that context.
  • A lambda expression can throw only those exceptions or the subtype of the exceptions for which an exception type is declared in the functional interface method's throws clause.
  • The parameter list of the lambda expression can declare a vararg parameter: (int ... i) -> {};
  • A Lambda Expression Is a Poly Expression- The type of a lambda expression is inferred from the target type thus the same lambda expression could have different types in different contexts. Such an expression is called a poly expression.

That's all for this topic Lambda Expressions in Java 8. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Java Lambda Expression as Method Parameter
  2. Java Lambda Expression And Variable Scope
  3. Method Reference in Java
  4. Java Stream API Tutorial
  5. Java Lambda Expressions Interview Questions And Answers

You may also like-

  1. How to Fix The Target Type of This Expression Must be a Functional Interface Error
  2. How to Resolve Local Variable Defined in an Enclosing Scope Must be Final or Effectively Final Error
  3. Java Exception Handling Tutorial
  4. Multi-Catch Statement in Java Exception Handling
  5. Covariant Return Type in Java
  6. static Import in Java With Examples
  7. How HashMap Works Internally in Java
  8. Difference Between yield And sleep in Java Multi-Threading

Wednesday, March 1, 2023

Map Operation in Java Stream API

Map operations in Java Stream API, as the name suggests, are used to do the element mapping from one stream to another. Map operation will return a stream consisting of the results of applying the given function to the elements of this stream. So, whatever function is provided is applied on all the elements of the stream.

One thing to note here is; since new stream is returned map operation is an intermediate operation.

map method in Java Stream

Java stream API provides the following map method.

<R> Stream<R> map(Function<? super T,? extends R> mapper)- Returns a stream consisting of the results of applying the given function to the elements of this stream.

Here R is the element type of the new stream, T denotes the element type of the existing stream and mapper is the function which will be applied to all the elements of the stream.

Here note that mapper is an instance of Function which is a functional interface. Since it is a functional interface therefore it can be used as the assignment target for a lambda expression or method reference.

map() method examples in Java Stream

  1. You have a stream of some names and you want to get a list where names are stored in upper case. In that case using map() method you can apply a function to all the elements of the stream to convert those elements to upper case and then using collector, collect them in a list.
    public class MappingDemo {
      public static void main(String[] args) {
        List<String> nameList = Stream.of("amy", "nick", "margo", "desi")
                                            .map(s->s.toUpperCase())
                                            .collect(Collectors.toList());
        System.out.println("Names in upper case" + nameList);
    
      }
    }
    

    Output

    Names in upper case[AMY, NICK, MARGO, DESI]
    
  2. You have a list of salaries and you want to increase salaries by 10%.
    List<Integer> myList = Arrays.asList(7000, 5000, 4000, 24000, 17000, 6000);  
    myList.stream().map(i -> (i+ (i * 10/100))).forEach(System.out::println);
    

    Output

    7700
    5500
    4400
    26400
    18700
    6600
    
  3. There is an employee class and you want the name of all the female employees. In this example you can use filter() method to filter female employees and then using map() method you can get the name of those employees. Here using map() method you are transforming employee object to String object.
    public class MappingDemo {
    
      public static void main(String[] args) {
        MappingDemo md = new MappingDemo();
        List<Employee> empList = md.createList();
        System.out.println("--- Name of female employees ---");
        empList.stream()
               .filter(e -> (e.getSex() == 'F'))
               .map(e -> e.getName())
               .forEach(System.out::println);
    
      }
        
      // Stub method to create list of employee objects
      private List<Employee> createList(){
        List<Employee> empList = Arrays.asList(new Employee("E001", 40, "Ram", 'M', 5000), 
                                       new Employee("E002", 35, "Sheila", 'F', 7000), 
                                       new Employee("E003", 24, "Mukesh", 'M', 9000), 
                                       new Employee("E004", 37, "Rani", 'F', 10000));
        
        return empList;
      }
      
      class Employee {
        private String empId;
        private int age;
        private String name;
        private char sex;
        private int salary;
        Employee(String empId, int age, String name, char sex, int salary){
          this.empId = empId;
          this.age = age;
          this.name = name;
          this.sex = sex;
          this.salary = salary;
        }
        public String getEmpId() {
          return empId;
        }
        public void setEmpId(String empId) {
          this.empId = empId;
        }
        public int getAge() {
          return age;
        }
        public void setAge(int age) {
          this.age = age;
        }
        public String getName() {
          return name;
        }
        public void setName(String name) {
          this.name = name;
        }
        public char getSex() {
          return sex;
        }
        public void setSex(char sex) {
          this.sex = sex;
        }
        public int getSalary() {
          return salary;
        }
        public void setSalary(int salary) {
          this.salary = salary;
        }       
      }
    }
    

    Output

    --- Name of female employees ---
    Sheila
    Rani
    

Variants of map() method

There are three variants of map() method which return a primitive stream.

  • mapToInt(ToIntFunction<? super T> mapper)- Returns an IntStream consisting of the results of applying the given function to the elements of this stream.
  • mapToDouble(ToDoubleFunction<? super T> mapper)- Returns a DoubleStream consisting of the results of applying the given function to the elements of this stream.
  • mapToLong(ToLongFunction<? super T> mapper)- Returns a LongStream consisting of the results of applying the given function to the elements of this stream.

Apart from that, in all the primitive type streams– IntStream, LongStream and Double Stream there is also a mapToObj() method.

For IntStream mapToObj() function is defined like this-

  • mapToObj(IntFunction<? extends U> mapper)- Returns an object-valued Stream consisting of the results of applying the given function to the elements of this stream.

map() method with primitive streams examples

  1. If you want to get the total of salaries for the employees (Using the employee class as above), you can use mapToInt() method to get an IntStream consisting of salaries and then apply sum() method on that int stream.
    int totalSalary = empList.stream().mapToInt(e -> e.getSalary()).sum();
    System.out.println("total of salaries " + totalSalary);
    

    Output

    total of salaries 31000
    
  2. If you want to get the maximum salary, you can use mapToInt() method to get an IntStream consisting of salaries and then apply max() method on that int stream to get the maximum salary.
    OptionalInt maxSalary = empList.stream().mapToInt(e -> e.getSalary()).max();
    if(maxSalary.isPresent()){
        System.out.println("Maximum Salary " + maxSalary.getAsInt());
    }
    

    Output

    Maximum Salary 10000
    
  3. For your testing you want to create 500 objects of some class -
    List<Employee> empList = IntStream.rangeClosed(1, 500).mapToObj(Employee::new).collect(Collectors.toList());
    

That's all for this topic Map Operation in Java Stream API. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Java Stream API Tutorial
  2. Parallel Stream in Java Stream API
  3. collect() Method And Collectors Class in Java Stream API
  4. Reduction Operations in Java Stream API
  5. @FunctionalInterface Annotation in Java

You may also like-

  1. New Date And Time API in Java With Examples
  2. Effectively Final in Java 8
  3. How HashMap Works Internally in Java
  4. Fail-Fast Vs Fail-Safe Iterator in Java
  5. Difference Between CountDownLatch And CyclicBarrier in Java
  6. Java ReentrantLock With Examples
  7. Find All Permutations of a Given String Java Program
  8. Spring Component Scan Example

Thursday, January 5, 2023

Reduction Operations in Java Stream API

Stream API contains many terminal operations (such as average, sum, min, max, and count) that return one value by combining the contents of a stream. These operations are called reduction operations in Java Stream API because these operations reduce the stream to a single non-stream value.

Examples of these reduction operations can be seen in the post Java Stream API Examples.

Apart from these above mentioned reduction operations, Java Stream API also provides general-purpose reduce methods that can be used with any user supplied logic to get a value from the stream.

Stream API in Java provides three versions of reduce() method-

  1. Optional<T> reduce(BinaryOperator<T> accumulator)- This reduce method returns an object of type Optional which contains the result. Notice that the result stored by Optional is of type T which also happens to be the element type of the stream.

    BinaryOperator is a functional interface which means it will have a single Abstract Method. Thus, accumulator is a function that will implement the method of the interface.
    If you see the description for BinaryOperator it says- Represents an operation upon two operands of the same type, producing a result of the same type as the operands.

    BinaryOperator extends another functional interface BiFunction which has this method-

    • R apply(T t, U u)- Applies this function to the given arguments.
    • Where R is the type of the result, T is the type of the first argument and U is the type of the second argument. (This explanation will help with the third form of the reduce method so please bear with me!).
    But in case of Binary Operator, as we have already seen in the explanation, two operands as well as the result are of same type so apply method effectively becomes T apply(T t, T u) in context of BinaryOperator.

    Here two things to note are-

    • When reduction is performed on the elements of this stream, using accumulation function (which is actually this apply method T apply(T t, Tu)) t will contain the previous result and u will contain the next element.
    • In the first invocation of this form of reduce method t will contain the first element.
  2. T reduce(T identity, BinaryOperator<T> accumulator)- This reduce method returns the result of type T which is same as the element type of the stream. The provided identity value must be an identity for the accumulator function. This means that for all t, accumulator.apply(identity, t) is equal to t i.e. applying the accumulation operation on the identity value and any element of the stream will give you back the element.

    For example, if the operation is addition then the identity value will be 0 as 0 + element = element, in case operation is multiplication then identity value is 1 as 1 * element = element.

  3. <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)- In the third form you can see there are three parameters where apart from identity and accumulator (which is a BiFunction, as explained above) function there is also a combiner function which is a BinaryOperator. Combiner function gives user a way to tell how partial results are to be combined. It becomes important in case parallel stream is used (we’ll see an example soon).

    Another thing you should have noticed is the return type, here it is different from the element type of the stream. In other two variants of the reduce method return type is either an object of Optional (where value stored in the Optional object is same as element type of the stream) or same as element type of the stream.

Java Stream API reduce method example

Let’s see some examples of the reduce method in Java Streams. For that lets take an Employee class where employee with maximum salary is needed as result. Using the first two variants it can be done as-

Employee class

public class Employee {
    private String lastName;
    private String firstName;
    private String empId;
    private int age;
    private int salary;
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getEmpId() {
        return empId;
    }
    public void setEmpId(String empId) {
        this.empId = empId;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }
}

Class with reduce methods

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class ReduceDemo {

    public static void main(String[] args) {       
        List<Employee> empList = createList();
        
        // Using reduce method which returns Optional object
        Optional<Employee> result = empList.stream().reduce((e1, e2) -> 
          e1.getSalary() > e2.getSalary() ? e1 : e2);
        if(result.isPresent()){
            System.out.println("Employee with max salary - " + result.get().getFirstName() 
             + " salary " + result.get().getSalary());
        }
        
        // Using reduce method with identity element
        Employee emp = empList.stream().reduce(new Employee(), (e1, e2) -> 
          e1.getSalary() > e2.getSalary() ? e1 : e2);
        System.out.println("Employee with max salary - " + emp.getFirstName() 
          + " salary " + emp.getSalary());
        
    }
    
    // /Stub method to create list of employee objects
    private static List createList(){
        List<Employee> empList = new ArrayList<Employee>();
        Employee emp = new Employee();
        emp.setEmpId("E001");
        emp.setAge(40);
        emp.setFirstName("Ram");
        emp.setLastName("Chandra");
        emp.setSalary(5000);
        empList.add(emp);
        emp = new Employee();
        emp.setEmpId("E002");
        emp.setAge(35);
        emp.setFirstName("Sheila");
        emp.setLastName("Baijal");
        emp.setSalary(7000);
        empList.add(emp);
        emp = new Employee();
        emp.setEmpId("E003");
        emp.setAge(24);
        emp.setFirstName("Mukesh");
        emp.setLastName("Rishi");
        emp.setSalary(9000);
        empList.add(emp);    
        return empList;
    }
}

Output

Employee with max salary - Mukesh salary 9000
Employee with max salary - Mukesh salary 9000

Reduce method with combiner example

Here let’s see why combiner is important. If there is a list of numbers and you want to get the product of square root of all the numbers then using reduce method, where no combiner is specified, it can be done as-

public class ReduceDemo1 {
    public static void main(String[] args) {        
        List<Double> numList = Arrays.asList(9.0, 4.0, 25.0);        
        double productOfSqrRoots = numList.parallelStream().reduce(1.0, (a, b) -> a * Math.sqrt(b));
        System.out.println("" + productOfSqrRoots);                
    }
}

This will give result as 6.344227580643384 which is not correct. It is happening because not specifying a combiner means accumulator function itself will be used as combiner function too. In that case when partial results are combined the square root is done again resulting in wrong value.

Correct way will be to define a combiner function which will just multiply the partial results.

public class ReduceDemo1 {
    public static void main(String[] args) {
        List<Double> numList = Arrays.asList(9.0, 4.0, 25.0);
        double productOfSqrRoots = numList.parallelStream().reduce(1.0, (a, b) -> 
          a * Math.sqrt(b), (a,b)->a*b);
        System.out.println("" + productOfSqrRoots);        
    }
}

Output

30.0

Here note that this problem will only happen when parallel stream is used if you are using normal stream then there won’t be any partial results to combine.

public class ReduceDemo1 {
    public static void main(String[] args) {        
        List<Double> numList = Arrays.asList(9.0, 4.0, 25.0);        
        double productOfSqrRoots = numList.stream().reduce(1.0, (a, b) -> a * Math.sqrt(b));
        System.out.println("" + productOfSqrRoots);        
    }
}

Since sequential stream is used here rather than parallelStream so you will get a correct output 30.0 now.

Sum using reduce method

Using the Employee class as used above if you want the sum of all the salaries you can do that using reduce method.

int salarySum = empList.stream().reduce(0, (sum, e) -> sum + e.getSalary(), Integer::sum);
System.out.println("Sum of all salaries " + salarySum); 

Though the explicit map-reduce form is more readable and therefore should usually be preferred. Using a chain of map and reduce to do the same thing-

int salarySum1 = empList.stream().mapToInt(Employee::getSalary).reduce(0, (s1, s2) -> s1+s2);
System.out.println("Sum of all salaries " + salarySum1);

This looks more readable, you are first getting the salary of all the employees using the map method and then using reduce method summing them.

That's all for this topic Reduction Operations in Java Stream API. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Java Stream API Tutorial
  2. collect() Method And Collectors Class in Java Stream API
  3. Spliterator in Java
  4. Interface Static Methods in Java
  5. Java Stream API Interview Questions And Answers

You may also like-

  1. Effectively Final in Java 8
  2. Covariant Return Type in Java
  3. Why wait(), notify() And notifyAll() Methods Are in Object Class And Not in Thread Class
  4. Blocking Methods in Java Concurrency
  5. Java ArrayBlockingQueue With Examples
  6. How to Sort an ArrayList in Descending Order in Java
  7. How HashMap Works Internally in Java
  8. Difference Between Checked And Unchecked Exceptions in Java

Sunday, December 11, 2022

Lambda Expression Examples in Java

As we have already seen in the post about Java lambda expressions, they implement the abstract method of the functional interface. In that way lambda expressions can provide a compact and easy to read code which is not repetitive by using them in place of anonymous classes.

Using functional interfaces with anonymous inner classes is a common pattern in Java, from Java 8 lambda expressions provide a better alternative by implementing the abstract method of the functional interface.

In this post we'll see some examples of lambda expressions in Java like Runnable as lambda expression, Comparator as lambda expression, lambda expression implementation of Predicate functional interface.

Runnable as Lambda expression example

It is very common to implement the run() method of Runnable interface as an anonymous class, now same can be done with lambda expression in fewer lines increasing readability.

public class RunnableLambda {
  public static void main(String[] args) {
    // Runnable using anonymous class
    new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println("Runnable with anonymous");
      }
    }).start();
    
    // Runnable using lambda
    new Thread(()->System.out.println("Runnable Lambda")).start();
  }
}

It can be seen how concise the implementation becomes with lambda expression.

Comparator as Lambda expression example

In this example we'll have a list of Person object and they are sorted on first name using Comparator.

Person class

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

  public String getLastName() {
    return lastName;
  }

  public int getAge() {
    return age;
  }
  public char getGender() {
    return gender;
  }
    
  public String toString(){
    StringBuffer sb = new StringBuffer();
    sb.append(getFirstName()).append(" ");
    sb.append(getLastName()).append(" ");
    sb.append(getAge()).append(" ");
    sb.append(getGender());
    return sb.toString();    
  }
}
// Functional interface
@FunctionalInterface
interface IMyInterface {
  Person getRef(String firstName, String lastName, int age, char gender);
}

public class LambdaExpressionDemo {
  public static void main(String[] args) {
    List<Person> personList = createList();
    
    // comparator implementation as anonymous class
    // and sorting the list element on the basis of first name
    Collections.sort(personList, new Comparator<Person>() {
      public int compare(Person a, Person b) {
        return a.getFirstName().compareTo(b.getFirstName());
      }
    });
        
    System.out.println("Sorted list with anonymous implementation");
    for(Person p : personList){
      System.out.print(p.getFirstName() + " ");
    }
        
    // creating the same list again to use with lambda expression
    personList = createList();
    // Providing the comparator functional interface compare
    /// method as lambda exression
    Collections.sort(personList, (Person a, Person b) -> 
        a.getFirstName().compareTo(b.getFirstName()));
    System.out.println("Sorted list with lambda implementation");
    // Using the new ForEach loop of Java 8 
    // used with lambda expression
    personList.forEach((per) -> System.out.print(per.getFirstName() + " "));
  }
    
  // Utitlity method to create list
  private static List<Person> createList(){
    List<Person> tempList = new ArrayList<Person>();
    IMyInterface createObj = Person::new;
    Person person = createObj.getRef("Ram","Tiwari", 50, 'M');
    tempList.add(person);
    person = createObj.getRef("Prem", "Chopra", 13, 'M');
    tempList.add(person);
    person = createObj.getRef("Tanuja", "Trivedi", 30, 'F');
    tempList.add(person);
    person = createObj.getRef("Manoj", "Sharma", 40, 'M');
    tempList.add(person);
    System.out.println("List elements are - ");
    System.out.println(tempList);
    return tempList;
  }
}

Output

List elements are - 
[Ram Tiwari 50 M, Prem Chopra 13 M, Tanuja Trivedi 30 F, Manoj Sharma 40 M]
Sorted list with anonymous implementation
Manoj Prem Ram Tanuja List elements are - 
[Ram Tiwari 50 M, Prem Chopra 13 M, Tanuja Trivedi 30 F, Manoj Sharma 40 M]
Sorted list with lambda implementation
Manoj Prem Ram Tanuja

Here I have used some of the features of Java 8 like Constructor reference using Double colon operator, which is this line IMyInterface createObj = Person::new;

Also used the new forEach statement in Java 8 with lambda expression, which is this line-

personList.forEach((per) -> System.out.print(per.getFirstName() + " "));

Same way lambda expression can be used with other functional interfaces like Callable, ActionListener etc.

Lambda expression with inbuilt functional interfaces

With Java 8 many new functional interfaces are being defined, in fact there is a whole new package java.util.function added with many functional interfaces. The interfaces in this package are general purpose functional interfaces used by the JDK, and are available to be used by user code as well.

The following are some of the examples of new functional interfaces in Java 8-

public interface Predicate<T> {
  boolean test(T t);
}
 
public interface Function<T,R> {
  R apply(T t);
}
 
public interface BinaryOperator<T> {
  T apply(T left, T right);
}
 
public interface Consumer<T> {
  void accept(T t);
}
 
public interface Supplier<T> {
  T get();
}

Starting with Java 8 these functional interfaces can be implemented by means of lambda expressions and method references.

We have already seen in the above examples how using lambda expressions we can solve the vertical problem associated with anonymous classes and make the code concise and more readable. Here let's see an example using one of the inbuilt functional interface.

Predicate functional interface as Lambda expression implementation

Supposing we want to use inbuilt functional interface named Predicate declared as follows:

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

We have a class person and using that person list we want to implement a search criteria where we want to search and print the following-

  1. List of drivers (age >= 16)
  2. List of voters (age >= 18)
  3. List of senior citizens (age >= 60)

We'll use the inbuilt functional interface Predicate to set up the search criteria. Note that we don’t need to explicitly write the Predicate interface as it is already available, we just need to import it from java.util.function package.

Person Class

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

  public String getLastName() {
    return lastName;
  }

  public int getAge() {
    return age;
  }
  public char getGender() {
    return gender;
  }
    
  public String toString(){
    StringBuffer sb = new StringBuffer();
    sb.append(getFirstName()).append(" ");
    sb.append(getLastName()).append(" ");
    sb.append(getAge()).append(" ");
    sb.append(getGender());
    return sb.toString();    
  }
}
@FunctionalInterface
interface IMyFunc {
  Person getRef(String firstName, String lastName, int age, char gender);
}

public class LambdaDemo {
    
  public static void main(String args[]){
    List<Person> personList = createList();
    ListPerson listPerson = new ListPerson();
    //Predicates
    // For age >= 16
    Predicate<Person> allDrivers = p -> p.getAge() >= 16;
    // For age >= 18
    Predicate<Person> allVoters = p -> p.getAge() >= 18;
    // For age >= 60
    Predicate<Person> allSeniorCitizens = p -> p.getAge() >= 60;
    // calling method to list drivers, passing predicate as arg
    listPerson.listDrivers(personList, allDrivers);
    
    // calling method to list voters, passing predicate as arg 
    listPerson.listVoters(personList, allVoters);
    
    // calling method to list senior citizens, passing predicate as arg 
    listPerson.listSeniorCitizens(personList, allSeniorCitizens);       
  }
    
  // Utitlity method to create list
  private static List<Person> createList(){
    List<Person> tempList = new ArrayList<Person>();
    // Constructor reference
    IMyFunc createObj = Person::new;
    Person person = createObj.getRef("Ram","Tiwari", 50, 'M');
    tempList.add(person);
    person = createObj.getRef("Prem", "Chopra", 13, 'M');
    tempList.add(person);
    person = createObj.getRef("Tanuja", "Trivedi", 30, 'F');
    tempList.add(person);
    person = createObj.getRef("Manoj", "Sharma", 40, 'M');
    tempList.add(person);
    person = createObj.getRef("John", "Trevor", 70, 'M');
    tempList.add(person);
    person = createObj.getRef("Alicia", "Sliver", 17, 'F');
    tempList.add(person);
    System.out.println("List elements are - ");
    System.out.println(tempList);
    return tempList;
  }
}

class ListPerson {
  // method to list drivers
  public void listDrivers(List<Person> personList, Predicate<Person> pred){
    List<Person> driverList = new ArrayList<Person>();
    for(Person person : personList){
      if (pred.test(person)){
        driverList.add(person);    
      }
    }
    System.out.println("List of drivers ");
    printList(driverList);
  }
    
  // method to list voters
  public void listVoters(List<Person> personList, Predicate<Person> pred){
    List<Person> voterList = new ArrayList<Person>();
    for(Person person : personList){
      if (pred.test(person)){
        voterList.add(person);    
      }
    }
    System.out.println("List of voters ");
    printList(voterList);
  }
    
  // method to list senior citizens
  public void listSeniorCitizens(List<Person> personList, Predicate<Person> pred){
    List<Person> seniorCitizenList = new ArrayList<Person>();
    for(Person person : personList){
      if (pred.test(person)){
        seniorCitizenList.add(person);    
      }
    }
    System.out.println("List of senior citizens ");
    printList(seniorCitizenList);
  }
 
  // Method used for printing the lists
  private void printList(List<Person> personList){
    personList.forEach((p) -> System.out.print(" FirstName - " + p.getFirstName()  
            + " LastName - " + p.getLastName() + " Age - " + p.getAge()));
    System.out.println("");
  }
}

It can be seen how concise and readable the code becomes and it is also non-repetitive, if we were using anonymous classes to write these search criteria we would have done the same chore of taking new instance of interface Predicate and overriding the test method for each search criteria. The anonymous class implementation for getting the list of drivers would have looked like this.

listPerson.listDrivers(personList, new Predicate<Person>(){
   @Override
   public boolean test(Person p){
       return p.getAge() >=16;
   }
});

So it can be seen how lambda expression can help with solving the vertical problem associated with anonymous class and provides a better alternative to provide implementation of functional interfaces.

That's all for this topic Lambda Expression Examples in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Functional Interface Annotation in Java
  2. Method Reference in Java
  3. How to Resolve Local Variable Defined in an Enclosing Scope Must be Final or Effectively Final Error
  4. Java Lambda Expression And Variable Scope
  5. Java Lambda Expressions Interview Questions And Answers

You may also like-

  1. How HashMap Works Internally in Java
  2. Executor And ExecutorService in Java With Examples
  3. final Vs finally Vs finalize in Java
  4. Difference Between throw And throws in Java
  5. static Method Overloading or Overriding in Java
  6. Covariant Return Type in Java
  7. Effectively Final in Java 8
  8. Interface Default Methods in Java 8

Monday, December 5, 2022

How to Resolve Local Variable Defined in an Enclosing Scope Must be Final or Effectively Final Error

This post talks about how to resolve "local variable defined in an enclosing scope must be final or effectively final" error while trying to write a lambda expression in Java.

Let's first get some background on what is effectively final; that will help you to get an idea why this error is coming.

Effectively Final in Java

When a lambda expression uses an assigned local variable from its enclosing space there is an important restriction.
A lambda expression may only use local variable whose value doesn't change. That restriction is referred as "variable capture" which is described as; lambda expression capture values, not variables. The local variables that a lambda expression may use are known as "effectively final".

An effectively final variable is one whose value does not change after it is first assigned. There is no need to explicitly declare such a variable as final, although doing so would not be an error. Since there is no need to explicitly declare such a variable as final thus the name effectively final. If there is an attempt to change such a variable, anyway compiler will throw an error.

Let's see it with an example. Here I have a functional interface IFunc which has a single abstract method display. Since it has a single abstract method it is a functional interface and lambda expression can be used to implement this functional interface. Just to make it clear I have also used the @Functional interface annotation.

In the code lambda expression that implements the display method of the interface just prints the value of the local variable on the console. It can be noted that there is no need to declare variable i as final which was a requirement before Java 8 (in case of anonymous class).

@FunctionalInterface
interface IFunc{
  void display();
}

public class InnerDemo { 
  public static void main(String[] args) {
    int i = 7;
    // lambda expression that implements the display method 
    // of the IFunc functional interface 
    IFunc ifunc = ()-> System.out.println("Value of i is " + i);
    // Calling the display method
    ifunc.display();
  }   
}

Output

Value of i is 7

It can be seen if we are not changing the value of local variable i, it can be used with lambda expression and there is no need to declare i as final.

When will it give error

As already pointed out while discussing effectively final "A lambda expression may only use local variable whose value doesn't change". So if you try to change the value of i with in the lambda expression you'll get the error "Local variable i defined in an enclosing scope must be final or effectively final".

Code that gives compiler error

@FunctionalInterface
interface  IFunc{
  void display();
}

public class InnerDemo {
  public static void main(String[] args) {
    int i = 7;
    // lambda expression that implements the display method 
    // of the IFunc functional interface 
    IFunc ifunc = ()-> System.out.println("Value of i is " + i++);
    // Calling the display method
    ifunc.display();
  }   
}

Here I have changed the i to i++ in System.out thus the program gives compile time error "Local variable i defined in an enclosing scope must be final or effectively final".

So it should be clear by now what it means for a variable to be effectively final and why do you get this error "local variable defined in an enclosing scope must be final or effectively final".

Solution to get around this error

Since it is a rule in Java programming language that variable in an enclosing scope can't be change in inner class or lambda expression, so you can't change the value of the variable. That said, there is a get around which I have used and that get around is to use array.

If we take the previous example again by using an int[] array instead of int variable-

@FunctionalInterface
interface  IFunc{
 void display();
}

public class InnerDemo {

  public static void main(String[] args) {
    int[] numArr = {7};
    // lambda expression that implements the display method 
    // of the IFunc functional interface 
    IFunc ifunc = ()-> System.out.println("Value of i is " + (numArr[0]+1));
    // Calling the display method
    ifunc.display();
  }
}

Output

Value of i is 8

As you can see it works now and "local variable defined in an enclosing scope must be final or effectively final" error is not thrown anymore.

Works very well with boolean flags and that's where I have used it. Let's see a small example.

public class Test{
 public static void main(String[] args) {
  List applications = Arrays.asList("A", "B");
  List user = Arrays.asList("A");
  Boolean[] arr = {true}; 
  applications.forEach( a -> {
   for (String str : user) {
    if(a.equals(str)) {
     //error resolved: Local variable flag defined in an enclosing scope must be final or effectively final
     arr[0] = false; 
     break;
    }else{
     arr[0] = true;
    }
   }
 
   if(!arr[0]) {
    System.out.println("Here with false");
   }else{
    System.out.println("Here with true");
   }
  });
 }
}

Output

Here with false
Here with true

That's all for this topic How to Resolve Local Variable Defined in an Enclosing Scope Must be Final or Effectively Final Error. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Lambda Expressions in Java 8
  2. Java Lambda Expression And Variable Scope
  3. How to Fix The Target Type of This Expression Must be a Functional Interface Error
  4. Method Reference in Java
  5. Java Lambda Expressions Interview Questions And Answers

You may also like-

  1. Multi-Catch Statement in Java Exception Handling
  2. Interface Static Methods in Java
  3. Java Stream API Examples
  4. Java Abstract Class and Abstract Method
  5. final Keyword in Java With Examples
  6. Java ThreadLocal Class With Examples
  7. How and Why to Synchronize ArrayList in Java
  8. Best Practices For Exception Handling in Java