Java Lambda 表達式使用

Java8 引入了 Lambda 表達式,使用 Lambda 表達式可讓代碼更加簡潔。Lambda 表達式其實也就是一個匿名函數,咱們能夠用它去代替匿名函數,咱們先來看一個例子java

一、Lambda 表達式語法

咱們用接口 Runnable 舉個例子express

public static void main(String[] args) {
        
    // 匿名函數
    new Thread(new Runnable() {
        public void run() {
            System.out.println("anonymous function");
        }
    }).start();
        
    // lambda 表達式
    new Thread(() -> System.out.println("lambda")).start();
}

從上的例子能夠看出咱們使用 () -> {} 的代碼塊代替了整個匿名函數app

Lambda 表達式的語法格式以下
( parameters ) -> expression
( parameters ) -> {statements;}函數

  • 能夠不須要聲明參數類型,編譯器能夠統一識別參數值。
  • 一個參數時能夠不定義圓括號,但多個參數須要定義圓括號。
  • 若是主體只有一個表達式返回值則編譯器會自動返回值,大括號須要指定明表達式返回了一個數值(若是接口方法返回類型爲 void 則不用)。

Lambda 表達式的簡單例子this

// 無參數,返回值爲 10
() -> 10  
  
// 單參數(數字類型),返回其2倍的值  
x -> 2 * x  
  
// 多個參數(數字),並返回他們的差值  
(x, y) -> x – y  
  
// 聲明參數類型,返回他們的和  
(int x, int y) -> return x + y  
  
// 聲明參數類型,並在控制檯打印,不返回任何值(接口方法返回類型爲 void)  
(String s) -> System.out.print(s)

二、Lambda 行爲參數化和變量做用域

咱們能夠將lambda表達式做爲參數傳遞給方法,也就是說容許把函數做爲一個方法的參數。code

建立一個 Calculator 的函數接口。 在 Calculator 中有一個稱爲 calculate 的方法,它接受兩個 int 參數並返回一個 int 值。 在 engine 方法中,它接受函數接口 Calculator 做爲參數。在主方法中,用不一樣的lambda表達式調用 engine 方法四次對象

public class LambdaTest {

    public static void main(String[] argv) {
        engine((x, y) -> x + y);
        engine((x, y) -> x * y);
        engine((x, y) -> x / y);
        engine((x, y) -> x % y);
    }

    private static void engine(Calculator calculator) {
        int x = 2, y = 4;
        int result = calculator.calculate(x, y);
        System.out.println(result);
    }
}

@FunctionalInterface
interface Calculator {
    int calculate(int x, int y);
}

lambda 表達式不定義本身的範圍。 若是咱們在 lambda 中使用關鍵字 thissuperthis 表明着 lambda 表達式所被包含的類接口

變量做用域作用域

lambda 表達式與其外部方法具備相同的範圍。 lambda表達式不會建立本身的做用域。get

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

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());  //編譯會出錯

三、函數式接口

函數式接口只是具備一個方法的接口,用做 lambda 表達式的類型。
一般會使用 @FunctionalInterface 註解來標註了函數式接口

在 java8 中爲咱們定義了不少經常使用的函數式接口,它們都放在java.util.function包下面,通常有如下經常使用的四大核心接口

函數式接口 參數類型 返回類型 描述
Consumer<T>(消費型接口) T void 對類型爲T的對象應用操做。void accept(T t)
Supplier<T>(供給型接口) T 返回類型爲T的對象。 T get();
Function<T, R>(函數型接口) T R 對類型爲T的對象應用操做並返回R類型的對象。R apply(T t);
Predicate<T>(斷言型接口) T boolean 肯定類型爲T的對象是否知足約束。boolean test(T t);

四、方法引用

方法引用經過方法的名字來指向一個方法。
方法引用可使語言的構造更緊湊簡潔,減小冗餘代碼。
方法引用使用一對冒號 ::

1)構造函數引用

使用構造函數引用的語法是 ClassName::new

Function<String,String> func1  = str ->  new String(str);

Function<String,String> func2  = String::new;

2) 靜態方法引用

方法引用的通常語法是 Qualifier::MethodName

Function<Integer, String> func1  = x -> Integer.toBinaryString(x);

Function<Integer, String> func2  = Integer::toBinaryString;

3) 實例方法引用

Supplier<Integer> supplier  = () ->  "www.w3cschool.cn".length(); 

Supplier<Integer> supplier1  = "www.w3cschool.cn"::length;

4) 通用方法引用

Function<String[],List<String>> asList = Arrays::<String>asList;
    
System.out.println(asList.apply(new String[]{"a","b","c"}));
相關文章
相關標籤/搜索