Thursday, July 8, 2021

ForEach Methods in Java 8

 

 

 

 

 

This method takes a single parameter which is a functional interface. So, you can pass lambda expression as an argument.


default void forEach(Consumer<super T>action) 

 

 
Exmaple of foreach() Method: 
 
import java.util.*;  
public class Example{  
    public static void main(String[] args) {       
       List<String> list=new ArrayList<String>();  
       list.add("a");         
       list.add("b");       
       list.add("b");         
       list.add("c");         
       list.add("d");                
       list.forEach(          
           // lambda expression        
           (names)->System.out.println(names)         
       );     
    }  
}
 
 
 
 

Default methods

 

 

 

 

A method in the interface that has a predefined body is known as the default method. It uses the keyword default. default methods were introduced in Java 8 to have 'Backward Compatibility in case JDK modifies any interfaces. 

 

In case a new abstract method is added to the interface, all classes implementing the interface will break and will have to implement the new method. 

 

With default methods, there will not be any impact on the interface implementing classes. default methods can be overridden if needed in the implementation. Also, it does not qualify as synchronized or final.

 

Default methods are declared using the new default keyword. These are accessible through the instance of the implementing class and can be overridden.

@FunctionalInterface // Annotation is optional 
public interface Foo() { 
// Default Method - Optional can be 0 or more 
public default String HelloWorld() { 
return "Hello World"; 
} 
// Single Abstract Method 
public void bar(); 
}

 

 This feature will help us in extending interfaces with additional methods, all we need is to provide a default implementation.

 

 

 Most Important Examples:


Scenerio1:

What if our class is implementing 2 interfaces and both of them have same default method.

Solution:

There can be 2 solution to this problem like below:


public interface Circle { default void print() { System.out.println("I am a circle!"); } }
public interface Square {

   default void print() {
      System.out.println("I am a Square!");
   }
}

 

 

First solution is to create an own method that overrides the default implementation.

 
 
public class Shape implements Circle, Square { public void print() { System.out.println("I am neither circle nor a square but I am a rectangle!"); } }

Second solution is to call the default method of the specified interface using super.

 

public class Shape implements Circle, Square {

   public void print() {
      Circle.super.print();
   }
}




 

 

 

 

 

 

 

Lambda Expression

 

 

 

 
Lambda expression is a new and important feature of Java which was included in Java SE 8. It provides a clear and concise way to represent one method interface using an expression.

 

A lambda expression is characterized by the following syntax.

(parameters) -> expression

 Java 8 Functional Interfaces and Lambda Expressions help us in writing smaller and cleaner code by removing a lot of boiler-plate code.

 

In general programming language, a Lambda expression (or function) is an anonymous function, i.e., a function with no name and any identifier.

 

The most important feature of Lambda Expressions is that they execute in the context of their appearance. So, a similar lambda expression can be executed differently in some other context (i.e. logic will be the same but results will be different based on different parameters passed to function).

 

Example: 

 

For example, the given lambda expression takes two parameters and returns their addition.

Based on the type of a and b, the expression will be used differently. If the parameters match to Integer the expression will add the two numbers. If the parameters of type String the expression will concat the two strings.

 

 (a, b) -> a + b    

 

One more Exmple of Lambda Expressions:

 
interface IntegerOperation {

    public String addTwoInteger(Integer a, Integer b);
} 
 
public class Example {

   public static void main(String args[]) {
        // lambda expression with multiple arguments
    	Integer s = (a, b) -> a + b;
        System.out.println("Result: " + s);
    }
}

 

 

 Important Points to be noted:

1. When there is a single parameter, if its type is inferred, it is not mandatory to use parentheses. 

 a -> return a*a.


2. If there are more than 1 statments in the body then they should be enclosed in the braces like below.


(parameters) -> { statements; }





Functional Interfaces

 

 

 

If you notice the above interface code, you will notice @FunctionalInterface annotation. Functional interfaces are a new concept introduced in Java 8. An interface with exactly one abstract method becomes a Functional Interface. We don’t need to use @FunctionalInterface annotation to mark an interface as a Functional Interface.

Functional interfaces are new additions in java 8 which permit exactly one abstract method inside them. These interfaces are also called Single Abstract Method interfaces (SAM Interfaces).

@FunctionalInterface annotation is a facility to avoid the accidental addition of abstract methods in the functional interfaces. You can think of it like @Override annotation and it’s best practice to use it. java.lang.Runnable with a single abstract method run() is a great example of a functional interface.

One of the major benefits of the functional interface is the possibility to use lambda expressions to instantiate them. We can instantiate an interface with an anonymous class but the code looks bulky.

 

Runnable r = new Runnable(){
            @Override
            public void run() {
                System.out.println("My Runnable");
            }};

Since functional interfaces have only one method, lambda expressions can easily provide the method implementation. We just need to provide method arguments and business logic. For example, we can write above implementation using lambda expression as:

Runnable r1 = () -> {
            System.out.println("My Runnable");
        };

If you have single statement in method implementation, we don’t need curly braces also. For example above Interface1 anonymous class can be instantiated using lambda as follows:

Interface1 i1 = (s) -> System.out.println(s);
         
i1.method1("abc");
 

So lambda expressions are a means to create anonymous classes of functional interfaces easily. There are no runtime benefits of using lambda expressions, so I will use it cautiously because I don’t mind writing a few extra lines of code.

A new package java.util.function has been added with bunch of functional interfaces to provide target types for lambda expressions and method references. Lambda expressions are a huge topic, I will write a separate article on that in the future.

 

 

Important Points to be noted in Functional Interfaces: 

1. only one abstract method is allowed in any functional interface. Second abstract method is not not permitted in a functional interface. If we remove @FunctionInterface annotation then we are allowed to add another abstract method, but it will make the interface non-functional interface.

 2. This is valid even if we are not using @FunctionalInterface annotation. It is only for informing the compiler to enforce single abstract method inside interface.

 3. Addition of default methods to the functional interface is acceptable as long as there is only one abstract method declaration:

You can follow the below example. 
 
@FunctionalInterface public interface Foo { String method(String string); default void defaultMethod() {} }
 
4.  

Java 8 new Features

 Java 8 new Features

 

 

Oracle released a new version of Java as Java 8 in March 18, 2014.

 Java 8 provides following new features:

  • Lambda expressions,
  • Method references,
  • Functional interfaces,
  • Stream API,
  • Default methods,
  • Base64 Encode Decode,
  • Static methods in interface,
  • Optional class,
  • Collectors class,
  • ForEach() method,
  • Parallel array sorting,
  • Nashorn JavaScript Engine,
  • Parallel Array Sorting,
  • Type and Repating Annotations,
  • IO Enhancements,
  • Concurrency Enhancements,
  • JDBC Enhancements etc.