Saturday, March 3, 2018

Functional Interface

If an interface contain only one abstract method, such type of interfaces are called functional interfaces and the method is called functional method or single abstract methods(SAM).

Ex:

1) Runnable –> it contains only run() method
2) Comparable –> it contains compareTo() method
3) ActionListener –> it contains only actionperformed()
4) Callable –> it contains only call() method

Inside functional interface in addition to Single Abstract Method(SAM) we write any number of default and static methods.
Ex:

Interface Interf {
             public abstract void m1(); 
               default void m2() {
                      System.out.println(hello);
               }
      }


In java 8, SunMicroSystem introduced @FunctionalInterface annotation to specify that the interface is FunctionalInterface.
Ex:

@FunctionalInterface
        Interface Interf {
            public void m1();
  }

this code compiles without any compilation errors.
Inside FunctionalInterface we can take only one abstract method, if we take more than one abstract method then compiler raise an error message that is called we will get compilation error.
Ex:

@FunctionalInterface {
        public void m1(); 
        public void m2();
  }

this code gives compilation error.
Inside FunctionalInterface we have to take exactly only one abstract method. If we are not declaring that abstract method then compiler gives an error message.
Ex:

@FunctionalInterface {
        interface Interface {
        } 
  }

this code gives compilation error.

FunctionalInterface with respect to Inheritence

If an interface extends FunctionalInterface and child interface doesn’t contain any abstract method then child interface is also FunctionalInterface.
Ex:

@FunctionalInterface 
interface A {
               public void methodOne();
            }

@FunctionalInterface
Interface B extends A {

     } 


In the child interface we can define exactly same parent interface abstract method.
Ex:

@FunctionalInterface
  interface A {
        Public void methodOne();
 }
 
@FunctionalInterface
 interface B extends A {
           public void methodOne();
 } 

In the child interface we can’t define any new abstract methods otherwise child interface won’t be FunctionalInterface and if we are trying to use @FunctionalInterface annotation then compiler gives an error message.

@FunctionalInterface {
 interface A {
       public void methodOne();
}
@FunctionalInterface
 interface B extends A {
     public void methodTwo();
}

this code is compilation error.
Ex:

@FuctinalInterface
     interface A {
          public void methodOne();
  }
  interface B extends A {
      public void methodTwo();
  }

In the above example in both parent and child interface we can write any number of default methods and there are no restrictions. Restrictions are applicable only for abstract methods.

FunctionalInterface Vs Lambda Expressions

Once we write Lambda expressions to invoke it’s functionality, then FunctionalInterface is required.
We can use FunctionalInterface reference to refer Lambda Expression.
Where ever FunctionalInterface concept is applicable there we can use Lambda Expressions.

Ex:1

Without Lambda Expression

interface interf {
 public void methodOne() {}
 public class Demo implements Interface {
      public void methodOne() {
             System.out.println(method one execution);
       }
        public class Test {
           public static void main(String[] args) {
                       Interfi = new Demo();
                  i.methodOne();
        }
}

Above code With Lambda Expression

interface Interf {
   public void methodOne() {}
   class Test {
         public static void main(String[] args) {
              Interfi = () 
               System.out.println(MethodOne Execution);
               i.methodOne();
         }
}


Without Lambda Expression

interface Interf {
          public void sum(int a, int b);
     }
     class Demo implements Interf {
                  public void sum(int a, int b) {
                       System.out.println(The sum: +(a+b));
                   }
     }
      public class Test  {
       public static void main(String[] args) {
               Interfi = new Demo();
               i.sum(20,5);
       }
     }

Above code With Lambda Expression

interface Interf {
          public void sum(int a, int b);
    }
    class Test {
            public static void main(String[] args) {
                 Interfi = (a,b)
                    Sytem.out.println(The sum: +(a,b));
                    i.sum(5,10);
            }
 }


Without Lambda Expressions

interface Interf {
          public int square(int x);
}
class Demo implements Interf {
          public int square(int x) {
              return x*x; OR (int x) -> x*x
         }
}
class Test {
    public static void main(String[] args) {
            Interfi = new Demo();
             System.out.println(The square of 7 is: +i.square(7));
       }
}

Above code with Lambda Expression

interface Interf {
     public int square(int x);
}
class Test {
          public static void main(String[] args) {
             Intrerfi = x -> x*x;
            System.out.println(The square of 5 is: +i.square(5));
           }
}

Without Lambda Expression

class MyRunnable implements Runnable {
                public void main() {
                      for (int i=0; i<10; i++)
                        System.out.println(Child Thread);
                     }
                }
     }
     class ThreadDemo {
            public static void main(String[] args) {
                        Runnable r = new myRunnable();
                   Thread t = new Thread(r);
                    t.start();
                    for(int i=0; i<10; i++)
                            System.out.println(Main Thread);
                   }
       }
    }

With Lambda Expression

class ThreadDemo {
          public static void main(String[] args) {
                    Runnable r = ()  {
                         for(int i=0;i<10; i++) {
                            System.out.println(Child Thread);
                        }
                 };
               Thread t = new Thread(r);
               t.start();
          for(i=0; i<10; i++) {
                System.out.println(Main Thread);
         }  
    }
}

Anonymous inner classes vs Lambda Expressions

Wherever we are using anonymous inner classes there may be a chance of using Lambda Expression to reduce length of the code and to resolve complexity.

Ex:

With anonymous inner class

class Test {
           public static void main(String[] args)
               Thread t = new Thread(new Runnable() {
                   public void run() { 
                         for(int i=0; i<10; i++) {
                               System.out.println(Child Thread);
                         }
                    }
            });
          t.start();
           for(int i=0; i<10; i++)
                  System.out.println(Main Thread);
            }
} 

With Lambda Expression

class Test {
        public static void main(String[] args) {
                  Thread t = new Thread(()  {
                                 for(int i=0; i<10; i++) {
                                 System.out.println(Child Thread);
                           }
          });
            t.start();
            for(int i=0; i<10; i++) {
               System.out.println(Main Thread);
            }
        }
}

What are the advantages of Lambda Expression?

--> We can reduce length of the code so that readability of the code will be improved.
--> We can resolve complexity of anonymous inner class.
--> We can provide Lambda expression in the place of object.
--> We can pass lambda expression as argument to methods.
Note

--> Anonymous inner class can extend concrete class, can extend abstract class, can implement interface with any number of methods.
--> Lambda expression can implement an interface with only single abstract method (FunctionalInterface).
--> Hence if anonymous inner class implements functionalinterface in that particular case only we can replace with lambda expressions. Hence
wherever anonymous inner class concept is there, it may not possible to replace with Lambda expressions.
--> Anonymous inner class! = Lambda Expression
--> Inside anonymous inner class we can declare instance variables.
--> Inside anonymous inner class “this” always refers current inner class object (anonymous inner class) but not related outer class object.

Ex:

--> Inside lambda expression we can’t declare instance variables.
--> Whatever the variables declare inside lambda expression are simply acts as local variables.
--> Within lambda expression “this” keyword represents current outer class object reference (that is current enclosing class reference in which
we declare lambda expression).

Ex:

interface Interf {
            public void m1();
}

class Test {
           int x = 777;
           public void m2() {
                      Interfi = ()
           {
                   int x = 888;
              System.out.println(x); 888
              System.out.println(this.x); 777
        };
          i.m1();
        }
        public static void main(String[] args) {
                    Test t = new Test();
                     t.m2();
       }
}

-->From lambda expression we can access enclosing class variables and enclosing method variables directly.
-->The local variables referenced from lambda expression are implicitly final and hence we can’t perform re-assignment for those local variables
otherwise we get compile time error.

Ex:

interface Interf {
           public void m1();
 }
  class Test {
              int x = 10;
              public void m2() {
                      int y = 20;
                      Interfi = ()
                {
                 System.out.println(x); 10
                 System.out.println(y); 20
                 x = 888;
                y = 999;    //CE
             };
                  i.m1();
                  y = 777;
            }
             public static void main(String[] args) {
                  Test t = new Test();
                    t.m2();
          }
  }

No comments: