<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] ***** # 第 18 章 Java 8函數式編程基礎——Lambda表達式 函數式編程將程序代碼看作數學中的函數,函數本身作為另一個函數的參數或返回值,即高階函數。 ## 18.1 Lambda表達式概述 ### 18.1.1 從一個示例開始 為了理解Lambda表達式的概念,下面先從一個示例開始。 假設有這樣的一個需求:設計一個通用方法,能夠實現兩個數值的加法和減法運算。Java中方法不能單獨存在,必須定義在類或接口中,考慮是一個通用方法,可以設計一個數值計算接口,其中定義該通用方法,代碼如下: ~~~ //Calculable.java文件 package com.a51work6; //可計算接口 public interface Calculable { // 計算兩個int數值 int calculateInt(int a, int b); } ~~~ Calculable接口只有一個方法calculateInt,參數是兩個int類型,返回值也是int類型。通過方法如下: ~~~ //HelloWorld.java文件 … /** * 通過操作符,進行計算 * @param opr 操作符 * @return 實現Calculable接口對象 */ public static Calculable calculate(char opr) { Calculable result; if (opr == '+') { // 匿名內部類實現Calculable接口,生成實例對象 result = new Calculable() { ① // 實現加法運算 @Override public int calculateInt(int a, int b) { ② return a + b; } }; } else { // 匿名內部類實現Calculable接口,生成實例對象 result = new Calculable() { ③ // 實現減法運算 @Override public int calculateInt(int a, int b) { ④ return a - b; } }; } return result; } ~~~ 通用方法calculate中的參數opr是運算符,返回值是實現Calculable接口對象。代碼第①行和第③行都采用匿名內部類實現Calculable接口。代碼第②行實現加法運算。代碼第④行實現減法運算。 調用通用方法代碼如下: ~~~ //HelloWorld.java文件 … public static void main(String[] args) { int n1 = 10; int n2 = 5; // 實現加法計算Calculable對象 Calculable f1 = calculate('+'); ① // 實現減法計算Calculable對象 Calculable f2 = calculate('-'); ② // 調用calculateInt方法進行加法計算 System.out.printf("%d + %d = %d \n", n1, n2, f1.calculateInt(n1, n2)); ③ // 調用calculateInt方法進行減法計算 System.out.printf("%d - %d = %d \n", n1, n2, f2.calculateInt(n1, n2)); ④ } ~~~ 代碼第①行中f1是實現加法計算Calculable對象,代碼第②行中f2是實現減法計算Calculable對象。代碼第③行和第④行才進行方法調用。 ### 18.1.2 Lambda表達式實現 Java 8采用Lambda表達式可以替代匿名內部類。修改之后的通用方法calculate代碼如下: lambda表達式用于生成只有一個方法的接口的實例對象,并重寫該接口的方法。 ~~~ // HelloWorld.java文件 … /** * 通過操作符,進行計算 * @param opr 操作符 * @return 實現Calculable接口對象 */ public static Calculable calculate(char opr) { Calculable result; if (opr == '+') { // Lambda表達式實現Calculable接口 result = (int a, int b) -> { //1 return a + b; }; } else { // result是Calculable類,Lambda表達式實現Calculable接口,并返回實現Calculable接口的實例對象。 result = (int a, int b) -> { //2 return a - b; }; } return result; } ~~~ 代碼第①行和第②行用Lambda表達式替代匿名內部類,可見代碼變得簡潔。 **Lambda表達式定義**:Lambda表達式是一個匿名函數(方法)代碼塊,可以作為表達式、方法參數和方法返回值。 Lambda表達式標準語法形式如下: ~~~ (參數列表) -> { //Lambda表達式體 } ~~~ 其中,Lambda表達式參數列表與接口中方法參數列表形式一樣,Lambda表達式體實現接口方法。 ***** result是Calculable類,Lambda表達式實現Calculable接口,并返回實現Calculable接口的實例對象。 ### 18.1.3 函數式接口 Lambda表達式實現的接口是函數式接口,這種接口只能有一個方法。 如果接口中聲明多個抽象方法,那么Lambda表達式會發生編譯錯誤: ~~~ The target type of this expression must be a functional interface ~~~ 這說明該接口不是函數式接口,為了防止在函數式接口中聲明多個抽象方法,Java 8提供了一個聲明函數式接口注解@FunctionalInterface,示例代碼如下。 ~~~ //Calculable.java文件 package com.a51work6; //可計算接口 @FunctionalInterface public interface Calculable { // 計算兩個int數值 int calculateInt(int a, int b); } ~~~ 在接口之前使用@FunctionalInterface注解修飾,那么試圖增加一個抽象方法時會發生編譯錯誤。但可以添加默認方法和靜態方法。 > **提示** Lambda表達式是一個匿名方法代碼,Java中的方法必須聲明在類或接口中,那么Lambda表達式所實現的匿名方法是在函數式接口中聲明的。 ## 18.2 Lambda表達式簡化形式 使用Lambda表達式是為了簡化程序代碼,Lambda表達式本身也提供了多種簡化形式,這些簡化形式雖然簡化了代碼,但客觀上使得代碼可讀性變差。本節介紹Lambda表達式本幾種簡化形式。 ### 18.2.1 省略參數類型 Lambda表達式可以根據上下文環境推斷出參數類型,所以可以省略參數類型: ~~~ public static Calculable calculate(char opr) { Calculable result; if (opr == '+') { // Lambda表達式實現Calculable接口 result = (a, b) -> { //1 return a + b; }; } else { // Lambda表達式可以省略參數類型 result = (a, b) -> { //2 return a - b; }; } return result; } ~~~ 上述代碼第①行和第②行的Lambda表達式是上一節示例的簡化寫法,其中a和b是參數。 ### 18.2.2 省略參數小括號 Lambda表達式中參數只有一個時,可以省略參數小括號。修改Calculable接口,代碼如下。 ~~~ //Calculable.java文件 package com.a51work6; //可計算接口 @FunctionalInterface public interface Calculable { // 計算一個int數值 int calculateInt(int a); } ~~~ 其中calculateInt方法只有一個int類型參數,返回值也是int類型。調用代碼如下: ~~~ //HelloWorld.java文件 package com.a51work6; public class HelloWorld { public static void main(String[] args) { int n1 = 10; // 實現二次方計算Calculable對象 Calculable f1 = calculate(2); // 實現三次方計算Calculable對象 Calculable f2 = calculate(3); // 調用calculateInt方法進行加法計算 System.out.printf("%d二次方 = %d \n", n1, f1.calculateInt(n1)); // 調用calculateInt方法進行減法計算 System.out.printf("%d三次方 = %d \n", n1, f2.calculateInt(n1)); } /** * 通過冪計算 * @param power 冪 * @return 實現Calculable接口對象 */ public static Calculable calculate(int power) { Calculable result; if (power == 2) { // Lambda表達式實現Calculable接口 result = (int a) -> { //標準形式 //1 return a * a; }; } else { // Lambda表達式實現Calculable接口 result = a -> { //函數式接口方法只有一個參數,lambda表達式省略了小括號 //2 return a * a * a; }; } return result; } } ~~~ 上述代碼第①行和第②行都是實現Calculable接口的Lambda表達式。代碼第①行是標準形式沒有任何的簡化。代碼第②行省略了參數類型和小括號。 ### 18.2.3 省略return和大括號 如果Lambda表達式體中只有一條語句,那么可以省略return和大括號,代碼如下: ~~~ public static Calculable calculate(int power) { Calculable result; if (power == 2) { // Lambda表達式實現Calculable接口 result = (int a) -> { //標準形式 return a * a; }; } else { // Lambda表達式實現Calculable接口,返回一個實例對象 result = a -> a * a * a; //函數式接口方法中只有一個參數和方法體只有一條語句,省略了小括號,花括號和return } return result; } ~~~ 上述代碼第①行是省略了return和大括號,這是最簡化形式的Lambda表達式。## 18.3 作為參數使用Lambda表達式 ## 18.3 作為參數使用Lambda表達式 Lambda表達式一種常見的用途是作為參數傳遞給方法。需要聲明參數的類型聲明為函數式接口類型。 示例代碼如下: ~~~ //HelloWorld.java文件 package com.a51work6; public class HelloWorld { public static void main(String[] args) { int n1 = 10; int n2 = 5; // 打印計算結果加法計算結果,Lambda表達式傳參 display((a, b) -> { return a + b; }, n1, n2); ① // 打印計算結果減法計算結果, Lambda表達式傳參 display((a, b) -> a - b, n1, n2); ② } /** * 打印計算結果 * * @param calc Lambda表達式 * @param n1 操作數1 * @param n2 操作數2 * Calculable 是函數式接口,只有一個方法的接口 */ public static void display(Calculable calc, int n1, int n2) { ③ System.out.println(calc.calculateInt(n1, n2)); } } ~~~ 上述代碼第③行定義display打印計算結果方法,其中參數calc類型是Calculable,這個參數即可以接收實現Calculable接口的對象,也可以接收Lambda表達式,因為Calculable是函數式接口。 代碼第①行和第②行兩次調用display方法,它們第一個參數都是Lambda表達式。 ## 18.4 訪問變量 Lambda表達式可以訪問所在外層作用域內定義的變量,包括:成員變量和局部變量。 ### 18.4.1 訪問成員變量 成員變量包括:實例成員變量和靜態成員變量。在Lambda表達式中可以訪問這些成員變量,此時的Lambda表達式與普通方法一樣,可以讀取成員變量,也可以修改成員變量。 示例代碼如下: ~~~ //LambdaDemo.java文件 package com.a51work6; public class LambdaDemo { // 實例成員變量 private int value = 10; // 靜態成員變量 private static int staticValue = 5; // 靜態方法,進行加法運算 public static Calculable add() { ① Calculable result = (int a, int b) -> { ② // 訪問靜態成員變量,不能訪問實例成員變量 staticValue++; int c = a + b + staticValue; // this.value; return c; }; return result; } // 實例方法,進行減法運算 public Calculable sub() { ③ Calculable result = (int a, int b) -> { ④ // 訪問靜態成員變量和實例成員變量 staticValue++; this.value++; int c = a - b - staticValue - this.value; return c; }; return result; } } ~~~ LambdaDemo類中聲明一個實例成員變量value和一個靜態成員變量staticValue。此外,還聲明了靜態方法add(見代碼第①行)和實例方法sub(見代碼第③行)。add方法是靜態方法,靜態方法中不能訪問實例成員變量,所以代碼第②行的Lambda表達式中也不能訪問實例成員變量,也不能訪問實例成員方法。 sub方法是實例方法,實例方法中能夠訪問靜態成員變量和實例成員變量,所以代碼第④行的Lambda表達式中可以訪問這些變量,當然實例方法和靜態方法也可以訪問,當訪問實例成員變量或實例方法時可以使用this。 ### 18.4.2 捕獲局部變量 對于成員變量的訪問Lambda表達式與普通方法沒有區別,但是對于訪問外層局部變量時,會發生“捕獲變量”情況。Lambda表達式中捕獲變量時,會將變量當成final的,在Lambda表達式中不能修改那些捕獲的變量。 示例代碼如下: ~~~ //LambdaDemo.java文件 package com.a51work6; public class LambdaDemo { // 實例成員變量 private int value = 10; // 靜態成員變量 private static int staticValue = 5; // 靜態方法,進行加法運算 public static Calculable add() { //局部變量 int localValue = 20; ① Calculable result = (int a, int b) -> { // localValue++; //編譯錯誤 ② int c = a + b + localValue; ③ return c; }; return result; } // 實例方法,進行減法運算 public Calculable sub() { //final局部變量 final int localValue = 20; ④ Calculable result = (int a, int b) -> { int c = a - b - staticValue - this.value; ⑤ // localValue = c; //編譯錯誤 ⑥ return c; }; return result; } } ~~~ 上述代碼第①行和第④行都聲明一個局部變量localValue,Lambda表達式中捕獲這個變量,見代碼第③行和第⑤行。不管這個變量是否顯式地使用final修飾,它都不能在Lambda表達式中修改變量,所以代碼第②行和第⑥行如果去掉注釋會發生編譯錯誤。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看