[Java學習筆記]JDK1.8新特性學習(一)Lambda表示式

DoneBug發表於2019-12-09

java8 新特性

Java8 新增了非常多的特性,我們主要討論以下幾個:

  1. Lambda 表示式
  • Lambda 允許把函式作為一個方法的引數(函式作為引數傳遞到方法中)。
  1. 方法引用
  • 方法引用提供了非常有用的語法,可以直接引用已有Java類或物件(例項)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗餘程式碼。
  1. 預設(Default)方法
  • 預設方法就是一個在介面裡面有了一個實現的方法。
  1. Stream API
  • 新新增的Stream API(java.util.stream) 把真正的函數語言程式設計風格引入到Java中。
  1. Date Time API
  • 加強對日期與時間的處理。
  1. Optional 類
  • Optional 類已經成為 Java 8 類庫的一部分,用來解決空指標異常

一、Lambda表示式

使用示例:

/**
*interface MathOperation {
*     int operation(int a, int b);
*}
**/

	// 1. 不需要引數,返回值為 5  
	() -> 5  
  
	// 2. 接收一個引數(數字型別),返回其2倍的值  
	x -> 2 * x  
  
	// 3. 接受2個引數(數字),並返回他們的差值  
	(x, y) -> x – y  
	  
	// 4. 接收2個int型整數,返回他們的和  
	(int x, int y) -> x + y  
	  
	// 5. 接受一個 string 物件,並在控制檯列印,不返回任何值(看起來像是返回void)  
	(String s) -> System.out.print(s)


      // 型別宣告,表示式主題內只有一條語句可以不用大括號{}
      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;
	  
	  

以下是lambda表示式的重要特徵:

  1. 可選型別宣告:不需要宣告引數型別,編譯器可以統一識別引數值
  2. 可選的引數圓括號:一個引數無需定義圓括號,但多個引數需要定義圓括號
  3. 可選的大括號:如果主體包含了一個語句,就不需要使用大括號。
  4. 可選的返回關鍵字:如果主體只有一個表示式返回值則編譯器會自動返回值,大括號需要指定明表示式返回了一個數值。

注意:

在 Lambda 表示式當中不允許宣告一個與區域性變數同名的引數或者區域性變數。

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

二、與集合forEach方法聯用

public class Java8Tester {
   public static void main(String args[]){
      List names = new ArrayList();
        
      names.add("Google");
      names.add("Runoob");
      names.add("Taobao");
      names.add("Baidu");
      names.add("Sina");
        
      names.forEach((anyThing)->System.out.println(anyThing));
   }
}

返回結果

Google
Runoob
Taobao
Baidu
Sina

原理:

forEach() 方法是Iterable介面中的一個方法。Java集合中,所有的Collection子類(List、Set)會實現Iteratable介面以實現foreach方法

public interface Iterable<T> {
 
    Iterator<T> iterator();
 
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
 
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

方法裡面有個Consumer型別,它是Java8新增的一個消費型函式式介面,其中的accept(T t)方法代表了接受一個輸入引數並且無返回的操作。

@FunctionalInterface
public interface Consumer<T> {
    /* 接收單個引數,返回為空 */
    void accept(T t);
 
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

回到最外層的程式碼

names.forEach((anyThing)->System.out.println(anyThing));

顯然,forEach括號內的Lambda表示式即實現accept方法構建了一個Consumer匿名物件,而jdk幫我們做的就是for迴圈每拿到一個元素,作為accept的引數傳入Consumer物件內供每次呼叫

三、總結:

Lambda 表示式主要用來定義行內執行的方法型別介面(通過代表實現方法主體以替代匿名內部類),例如,一個簡單方法介面。在上面例子中,我們使用各種型別的Lambda表示式來定義MathOperation介面的方法。然後我們定義了operation方法的執行主體。

相關文章