Lambda Expressions

Lambda

匿名內部類已經是一種簡潔的表示方法了,但是還有一個問題,例如一個接口,它只含有一個方法,那麼匿名內部類就不那麼易於使用了,因爲會出現很多冗餘的代碼,這個時候開發者就會想要將函數當成一個參數傳遞給一個方法,例如爲控件設置點擊事件。所以就出現了Lambda表達式,Java8引入了這個新特性,使用Android Studio編程時,會發現爲控件設置點擊事件的代碼會“變樣”,如下第二種表示方式就是Lambda表達式,既然官方都這樣用了,那我們還有什麼理由不擁抱這種方式呢。

 view.setOnClickListener(new View.OnClickListener() {//明明是這樣寫的
            @Override
            public void onClick(View v) {

            }
        });

  view.setOnClickListener((v) -> {//有的時候代碼看上去變成了這樣

        });  
  • 用法

    • Android Studio配置:

      android {
          buildToolsVersion "24.0.0"//大於24即可
          defaultConfig {
              jackOptions {
                  enabled true
              }
          }
          compileOptions {
              sourceCompatibility JavaVersion.VERSION_1_8
              targetCompatibility JavaVersion.VERSION_1_8
          }
      }
    • 語法

      • Lambda表達式只適用於只含有一個方法的接口
      • Lambda表達式的結構:(Type params) -> {block},整個表達式代表的是“接口的實現類”;params代表這個“接口中的方法的形參”;Type代表“形參的類型”,可以省略;block代表“接口中方法的實現“,具體請看下面的例子;
         public interface ISyntax {//Lambda表達式只適用於只含有一個方法的接口
          int getInt(int i);
      }
      
      private void invokeSyntax(ISyntax s) {//調用這個方法需要傳遞ISyntax的實現類
          s.getInt(10);
      }
      
      private void learnSyntax() {
          //匿名內部類已經省略了聲明對象這個步驟,看起來很簡潔了。
          invokeSyntax(new ISyntax() {
              @Override
              public int getInt(int i) {
                  return i++;
              }
          });
      
           // Lambda表達式其實也是匿名的,只不過不僅僅匿了對象名稱,還匿了類名,方法名
          invokeSyntax((int i) -> { //這裏的int i就是接口ISyntax中的getInt()方法中的參數
              return i++; //大括號中的內容就是getInt()方法的實現
          });
      
          invokeSyntax((i) -> i++);//可以省略參數類型,還可以省略大括號和“return”,直接寫返回值
      }
      • 作用域
      import java.util.function.Consumer;
      
      public class LambdaScopeTest {
      
          public int x = 0;
      
          class FirstLevel {
      
              public int x = 1;
      
              void methodInFirstLevel(int x) {
      
                  // The following statement causes the compiler to generate
                  // the error "local variables referenced from a lambda expression
                  // must be final or effectively final" in statement A:
                  //
                  // x = 99;
      
                  Consumer<Integer> myConsumer = (y) -> 
                  {
                      System.out.println("x = " + x); // Statement A
                      System.out.println("y = " + y);
                      System.out.println("this.x = " + this.x);
                      System.out.println("LambdaScopeTest.this.x = " +
                          LambdaScopeTest.this.x);
                  };
      
                  myConsumer.accept(x);
      
              }
          }
      
          public static void main(String... args) {
              LambdaScopeTest st = new LambdaScopeTest();
              LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
              fl.methodInFirstLevel(23);
          }
      }
      This example generates the following output:
      
      x = 23
      y = 23
      this.x = 1
      LambdaScopeTest.this.x = 0
      • 返回類型

        Lambda表達式只含有形參列表和實現代碼塊,那麼Java如何判斷一個Lambda表達式代表的究竟是哪個接口的實現類呢?看下面的例子:

         //Target Type
        public interface IInteger {
            void setInt(int i);
        }
        
        public interface IString {
            void setString(String str);
        }
        
        public interface IMultiParams {
            void setString(String str1, String str2);
        }
        
        public interface IReturn {
            String getString(String str);
        }
        
        private void use(IInteger e) {
            e.setInt(1);
        }
        
        private void use(IString t) {
            t.setString("IString");
        }
        
        private void use(IMultiParams m) {
            m.setString("param1", "param2");
        }
        
        private void use(IReturn r) {
            r.getString("IReturn");
        }
        
        public void learnTargetType() {
            //IInteger
            use((int i) -> {//該Lambda代表的是IInteger的實現類,因爲參數聲明瞭爲int類型
                Log.d(TAG, "i: " + i);
            });
            //IString
            use((String str) -> {
                Log.d(TAG, "str: " + str);
            });
            //IMultiParams
            use((param1, param2) -> {
                Log.d(TAG, "param1: " + param1 + " param2: " + param2);
            });
            //IReturn
            use((String str) -> "我有返回值" + str);
        }

        官網總結了以下幾點判斷Target Type(目標類型)的方法

        • Variable declarations 變量聲明

        • Assignments

        • Return statements 返回值聲明

        • Array initializers 數組初始化

        • Method or constructor arguments 方法或構造函數參數

        • Lambda expression bodies Lambda表達式代碼塊

        • Conditional expressions, ?: 條件表達式

        • Cast expressions

    • 優點

      • Lambda表達式其實就是匿名函數,簡潔,去除了沒有實際意義的代碼;
    • 缺點
      • 這個也不算是缺點,使用Lambda表達式必須要對函數非常的熟悉,知道它含有什麼參數;

參考文章:Oracle官網Android開發者網站

發佈了38 篇原創文章 · 獲贊 45 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章