Java 8 Lambda表達式學習和理解


Java 8 Lambda表達式和理解

說明:部分資料來源於網絡

時間:20190704

Lambda 表達式,也可稱為閉包,它是推動 Java 8 發布的最重要新特性。Lambda 允許把函數作為一個方法的參數(函數作為參數傳遞進方法中)。使用 Lambda 表達式可以使代碼變的更加簡潔緊湊。

 

一、語法

1、lambda 表達式的語法格式如下:

  (左邊)輸入參數->(右邊)lambda主體

(parameters) -> expression;

  或

(parameters) ->{ statements; }

 

2、以下是lambda表達式的重要特征:

(1)輸入參數:

  可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。

  可選的參數圓括號:

    a、一個參數無需定義圓括號,但多個參數需要定義圓括號。

    b、如果申明了參數類型,則一定需要圓括號。

(2)lambda主體

  可選的大括號:如果主體包含了一個語句,就不需要使用大括號。

  可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值

 

3、按照上面的格式,lambda不同參數的表達式寫法

(1)沒有參數的表達式:

() -> System.out.println("this is no parameter Lambda expression");

(2)只有一個參數的表達式:

(x) -> System.out.println("this is only one parameter Lambda expression");

  或者

(X x) -> System.out.println("this is only one parameter Lambda expression");

  和

(x) -> {
    x = x*2;
    System.out.println("this is only one parameter Lambda expression");
    System.out.println("the function is double input value");
    return x;
};

  說明:一個參數的可以不用使用(),如果參數聲明了參數類型則必須要加()Lambda主體是語句塊的話需要使用{}

(3)有兩個或者多個參數的表達式:

(x,y) -> System.out.println("these are several parameters Lambda expression");

  或者

(X x,Y y) -> {
  System.out.println("the function is add two input values");
  System.out.println("these are several parameters Lambda expression");
  return x+y;
};

  說明:有多個參數的lambda表達式,參數使用,隔開。Lambda主體是語句塊的話需要使用{}

 

二、Lambda 表達式實例

lambda示例1:

/*
 * Predicate<T>接口中boolean test(T t)方法只接收一個參數,返回值為boolean類型,
 * 故lambda表達式的輸入參數只有一個參數:x,lambda的主體返回值為boolean類型
 */
Predicate<Integer> atLeast5 = x -> x >= 5;
System.out.println("傳入參數是否大於5:" + atLeast5.test(6));

/*
 * BinaryOperator<T>接口中R apply(T t, U u)方法接收兩個泛型參數,返回值為也為泛型
 * 故lambda表達式輸入Long參數有兩個:x,y,lambda的主體返回值為Long類型
 */
BinaryOperator<Long> addLongs = (x, y) -> {
  Long z = x + y;
  return z;
};
System.out.println("計算傳入兩個Long參數的和:" + addLongs.apply(5l, 6l));

/*
 * Runnable接口中run()方法沒有參數,有沒有返回值,故lambda表達式沒有參數,lambda主體也沒有返回值
 */
Runnable run1 = () -> System.out.println("這個方法就是run里面的方法");
run1.run();

try {
  final Integer value = 9;
  /*
   *  1、Callable<V>接口中V call() throws Exception方法沒有參數,故lambda表達式也不能有輸入參數,
   * 返回類型為泛型,故lambda主體需要返回指定Integer類型
   *  2、因為.call()方法拋出異常,所以需要拋出或者捕獲異常
   *  3、lambda表達式使用外部參數,需要是final類型,及時外部參數沒有定義為final類型,
   * 也會隱式的指定為final,故值或者引用地址不能修改。
   */
  Callable<Integer> call = () -> value;
  System.out.println("無參的方法,所以lambda的參數列表中不能傳遞參數:" + call.call());
} catch (Exception e) {
  e.printStackTrace();
}

lambda示例二:

public class Java8Tester { 

  public static void main(String args[]){ 
    Java8Tester tester
= new Java8Tester();     // 類型聲明     MathOperation addition = (int a, int b) -> a + b;     // 不用類型聲明     MathOperation subtraction = (a, b) -> a - b;     // 大括號中的返回語句     MathOperation multiplication = (int a, int b) -> { return a * b; };     // 沒有大括號及返回語句     MathOperation division = (int a, int b) -> a / b;     System.out.println("10 + 5 = " + tester.operate(10, 5, addition));     System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));     System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));     System.out.println("10 / 5 = " + tester.operate(10, 5, division));     // 不用括號     GreetingService greetService1 = message -> System.out.println("Hello " + message);     // 用括號     GreetingService greetService2 = (message) -> System.out.println("Hello " + message);     greetService1.sayMessage("Runoob");     greetService2.sayMessage("Google");   }

  // 定義接口和接口中為實現的方法   
interface MathOperation {
    int operation(int a, int b);
  }

  // 定義接口和接口中為實現的方法
  interface GreetingService {
    void sayMessage(String message);
  }

  // 定義方法,方法通過lambda表達式實現了接口中的方法   
private int operate(int a, int b, MathOperation mathOperation){     return mathOperation.operation(a, b);   } }

執行以上代碼,輸出結果為:

10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Runoob
Hello Google

使用 Lambda 表達式需要注意以下兩點:

Lambda表達式主要用來定義行內執行的方法類型接口,例如,一個簡單方法接口。在上面例子中,我們使用各種類型的Lambda表達式來定義MathOperation接口的方法。然后我們定義了sayMessage的執行。

Lambda 表達式免去了使用匿名方法的麻煩,並且給予Java簡單但是強大的函數化的編程能力。

Lambda表達式常用的場景是:函數式接口。函數式接口是指的只有一個抽象方法的接口,我們常用的函數式接口有:

Runnable、Callable、PrivilegedAction、Comparator、FileFilter、PathMatcher、InvocationHandler、PropertyChangeListener、ActionListener、ChangeListener、Function、Predicate、BinaryOperator

 

三、lambda表達式中的變量作用域

lambda表達式只能引用標記了final的外層局部變量,這就是說不能在lambda內部修改定義在域外的局部變量,否則會編譯錯誤。

Java8Tester.java 文件輸入以下代碼:

public class Java8Tester {

  final static String salutation = "Hello! "; 

  public static void main(String args[]){
    GreetingService greetService1
= message -> System.out.println(salutation + message);     greetService1.sayMessage("Runoob");     //====================相當於下面==============================     GreetingService g = new GreetingService() {       @Override       public void sayMessage(String message) {         System.out.println(salutation + message);       }     };     g.sayMessage("jack");
  }   
interface GreetingService {     void sayMessage(String message);   } }

執行以上腳本,輸出結果為:

$ javac Java8Tester.java 
$ java Java8Tester
Hello! Runoob
Hello! jack

我們也可以直接在 lambda 表達式中訪問外層的局部變量:

public class Java8Tester { 

  public static void main(String args[]) { 
    final int num = 1; 
    Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); 
    s.convert(2); // 輸出結果為 3 
  } 

  public interface Converter<T1, T2> { 
    void convert(int i); 
  } 
}

lambda表達式的局部變量可以不聲明為final,但是不可被后面的代碼修改(即隱性的具有final 的語義)

int num = 1;  
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5;  //報錯信息:Local variable num defined in an enclosing scope must be final or effectively final

Lambda 表達式當中不允許聲明一個與局部變量同名的參數或者局部變量。

String first = "";  
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());  //編譯會出錯

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM