Java 8 - Lambda expressions (Introduction and purpose) with examples


Hi, I am Malathi Boggavarapu working at Volvo Group and i live in Gothenburg, Sweden. I have been working on Java since several years and had vast experience and knowledge across various technologies.

This post teach you about Java 8 - Lambda expressions using some practical examples

Introduction to Lambda expressions


To understand it easily, lets start with FileFilter example.

public interface Filefilter{
    boolean  accept(File file);
}

public class JavaFileFilter implements FileFilter{
    boolean accept(File file){
         return file.getName().endsWith(".java")
   }
}

JavaFileFilter fileFilter = new JavaFileFilter();
File dir = new File("d:/tmp");
File[] files = dir.listFiles(fileFilter);


2)

FileFilter fileFilter = new FileFilter(){
      boolean accept(File file){
         file.getName().endsWith(".java");
     }
};

File dir = new File("d:/tmp");
File[] files = dir.listFiles(fileFilter);

Purpose of Lambda expressions

It is an another way of writing instances of anonymous classes and to make instances of anonymous classes easier to write and read!

Example 1:

FileFilter filter = (File file) -> file.getName().endsWith(".java");

If more than one arguments then,

FileFilter filter = (File file, boolean test) -> {
   file.getName().endsWith(".java");
   println("test variable is :: " +test);
}

Example 2:

Runnable runnable = new Runnable(){
      public void run(){
           for(int i = 0; i < 10; i++){
               println("i : " +i);
           }
     }
}

Runnable runnableLambda = () -> {
      for(int i = 0; i < 10; i++){
               println("i : " +i);
     }
};

Type of lambda expression?

Type is a functional interface - interface with only one abstract method
Ex: public interface Runnable{
 run();
};
interface comparator(){
  int compareTo();
}

Methods from object class don't count. If we declare some method from Object class, we need to define some documentation for that abstract method in the functional interface.

Functional interface can be annotated with @FunctionalInterface and it is optional. .
The compiler will check whether interface is functional or not if we annotate it. If the interface is not a FunctionalInterface then it throws an exception and the code does not compile

Can i put lambda in variable?

Yes! Lambda expressions can be stored in a variable and pass them as arguments to methods and return them as return values.

Is a lambda expression an object?

If we see above examples, we have anonymous class and lambda expression. Anonymous class is created using keyword new. When we create an object with new keyword, it allocates some memory to the object, initiate static variables and call a constructor and so on. There is lot of overhead work done by the JVM here but in case of lambda all this overhead work does not exists and provide better performance than anonymous classes.

It is a complex question to answer. JVM does not create a new object with lambda expression and the answer is No but not a clear No. Because it is recorded as an object inside the JVM and  it is actually a new kind of object defined in java 8. Lambda is an object without an identity.

Lambda expression should not be used as an object.

Method references

Method references are the other way of writing lambda expression that is strictly equivalent to the normal way as writing lambda expressions.

Examples

1) This lambda expression:
Consumer<String> c = s-> System.out.println(s);

Can be written like this
Consumer<String> c =  System::out.println;

2) This lambda expression
Comparator<Integer> c = (i1, i2) -> Integer.compare(i1, i2);

can be written like this
Comparator<Integer> c = Integer::compare;

Processing data objects using Lambda expressions and Stream API

Usually objects will be stored in Collection (List, Map, Set) most of the time. So we will see here how the objects are accessed using lambda expressions.

List<Customer> list = new ArrayList<Customer>();

1) list.forEach(customer -> System.out.println(customer));
2) list.forEach(System.out::println(customer));

Performance is same for both the above ways. Only readability matters

forEach is a method in Iterable interface. Well..in java8 we can add method implementation inside the interface. It allows to change the old interfaces without breaking the existing implementations. If we see forEach method in Iterable interface, according to Java7 it should be implemented in all classes which implements Iterable. But that is not possible to do. Though it is possible for jdk developers to change all the implementation classes, it does not work with custom Iterable implementation classes that exists in applications.

And by the way static methods are also allowed in interfaces. Earlier only static final variables are only allowed but now static methods are allowed too.

public interface Iterable<E>{
    default void forEach(Consumer<E> consumer){
          for(E e : this){
              consumer.accept(e);
          }
    }
}

New patterns

Predicate : Is the functional interface inside java.util.Function
Predicate<String> p1 = < -> s.length() < 20;
Predicate<String> p2 = < -> s.length() > 10;

Predicate<String> p3 = p1.and(p2);

"and" is the default method inside the functional interface of Predicate.

Example

List<String> strings = Arrays.asList("one", "two", "Three");
List<String> result = new ArrayList<String>();

//Consumer<String> c1 = s -> System.out.println(s);
Consumer<String> c1 = System.out::println(c1); // Method reference

//Consumer<String> c2 = s -> result.add(s);
Consumer<String> c2 = result::add; // Method reference

strings.forEach(c1.andThen(c2));

Here addThen is the default implementation method of Consumer functional interface.

Comments

Post a Comment

Popular posts from this blog

Bash - Execute Pl/Sql script from Shell script

Gradle Fundamentals

Load Balancing using Spring Cloud Netflix Ribbon