12/08/2018, 14:47

Lambda và Anonymous Inner class làm việc thế nào

Anonymous inner class và Lambda trong Java có nhiều điểm tương đồng, nhưng hiểu được những điểm khác nhau giữa chúng cũng rất quan trọng và hữu ích trong công việc của lập trình viên. Bài viết này sẽ nêu ra một số điểm khác nhau giữa Lambda và Anonymous inner class, và cách thức làm việc của chúng. ...

Anonymous inner class và Lambda trong Java có nhiều điểm tương đồng, nhưng hiểu được những điểm khác nhau giữa chúng cũng rất quan trọng và hữu ích trong công việc của lập trình viên. Bài viết này sẽ nêu ra một số điểm khác nhau giữa Lambda và Anonymous inner class, và cách thức làm việc của chúng.

1. Nhắc lại khái niệm

  • Anonymous inner class: Inner class là class (non static) được viết trong một class khác (out-class). Anonymous class là Inner class nhưng không có 'class' đặt trước tên của class. Ví dụ.
interface AnonymousInner {
   public mymethod();
}

public class Outer_class {

   public static void main(String args[]) {
      AnonymousInner inner = new AnonymousInner() {
         @Override
         public void mymethod() {
            System.out.println("This is an example of anonymous inner class");
         }
      };
      inner.mymethod();	
   }
}
// out put when execute the program: This is an example of anonymous inner class
  • Lambdas: Lambada Expressions là một trong những tính năng mới, quan trọng của Java 8. Nó cung cấp cách thức rõ ràng và khúc triêt cách mô tả một method của một interface bằng cách dùng biểu thức. Lambda Expression cũng cung cấp các thư viện giúp cải tiến cách thưc làm việc với Collection như duyệt, filter, và truy xuất dữ liệu.
public class RunnableTest {
    public static void main(String[] args) {
      
      System.out.println("=== RunnableTest ===");
     
     // Anonymous Runnable
     Runnable r1 = new Runnable(){
       
       @Override
       public void run(){
         System.out.println("Hello world one!");
       }
     };
     
     // Lambda Runnable
     Runnable r2 = () -> System.out.println("Hello world two!");
     // Run em!
     r1.run();
     r2.run();     
   }
}

2. Những điểm khác nhau

  • Lambdas chỉ thực thi Functional Interface
  • Anonymous inner class có thẻ extends class, impliments interface với số lượng method bất kỳ.
  • Lambdas chỉ truy cập biến final hay effectively final.
  • Anonymous inner class thì có thể truy cập biến final và biến thông thường.
  • Khi biên dịch, Lambdas được biên dịch thành lệnh invokedynamic
  • Anonymous inner class được biên dịch thành class thông thường.

3. Cách thức làm việc

  • Như đã nói ở trên, trình biên dịch sẽ biên dịch Anonymous inner class thành class file thông thường. -Ví dụ: AnonymousInnerClass$1.class, AnonymousInnerClass$$.class,... Cũng như các class thông thường, Anonymous inner class được load và verify khi start chương trình.
  • Lambda thì làm việc như sau:
  • Lambdas được convert thành private static method của class chưa nó.
  • Method được gọi bởi method metafactory() của lớp LambdaMetafactory
  • Có hai loại Labdas là Non-capturing lambdas, và Capturing lambdas Non-capturing lambdas Là Lambdas không truy cập các field ngoài phạm vi của nó (blog code)
public class NonCapturingLambda {     
  public static void main(String[] args) {        
    Runnable nonCapturingLambda = () -> System.out.println("NonCapturingLambda");        
    nonCapturingLambda.run();     
  } }

Capturing bambdas Là Lamdas truy cập đến final effectively final field bên ngoài nó (blog code)

public class CapturingLambda {     
    public static void main(String[] args) 
    {         
        String effectivelyFinal = "effectivelyFinal";         
        Runnable capturingLambda = () -> System.out.println("capturingLambda " + effectivelyFinal);         
        capturingLambda.run();     } 
}

Giờ ta hãy xem cấu trúc được dịch ngược sau khi Lambdas được biên dịch.

  • Dịch ngược Non-capturing lambdas.
java -jar cfr_0_119.jar NonCapturingLambda --decodelambdas false 
/*  * Decompiled with CFR 0_119.  */ 
import java.io.PrintStream; 
import java.lang.invoke.LambdaMetafactory; 
public class NonCapturingLambda {     
    public static void main(String[] args) {         
        Runnable nonCapturingLambda = (Runnable)LambdaMetafactory.metafactory(null, 
           null, null, ()V, lambda$0(), ()V)();        
        nonCapturingLambda.run();     
    }     
    private static /* synthetic */ void lambda$0() 
    {         System.out.println("NonCapturingLambda");     
    } 
}
  • Dịch ngược Capturing lambdas.
java -jar cfr_0_119.jar CapturingLambda --decodelambdas false 
/*  * Decompiled with CFR 0_119.  */ 
import java.io.PrintStream; 
import java.lang.invoke.LambdaMetafactory; 
public class CapturingLambda {     
    public static void main(String[] args) {        
        String effectivelyFinal = "effectivelyFinal";         
        Runnable capturingLambda = 
          (Runnable)LambdaMetafactory.metafactory(null, null, null, ()V, 
                                                  lambda$0(java.lang.String ), 
                                                  ()V)((String)effectivelyFinal); 
          capturingLambda.run();     
    }     
    private static /* synthetic */ void lambda$0(String string) {         
        System.out.println("capturingLambda " + string);     
    } 
}

0