Java8 引入了 Lambda 表達式,使用 Lambda 表達式可讓代碼更加簡潔。Lambda 表達式其實也就是一個匿名函數,咱們能夠用它去代替匿名函數,咱們先來看一個例子java
咱們用接口 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表達式做爲參數傳遞給方法,也就是說容許把函數做爲一個方法的參數。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 中使用關鍵字
this
和super
,this
表明着 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); |
方法引用經過方法的名字來指向一個方法。
方法引用可使語言的構造更緊湊簡潔,減小冗餘代碼。
方法引用使用一對冒號 ::
使用構造函數引用的語法是 ClassName::new
Function<String,String> func1 = str -> new String(str); Function<String,String> func2 = String::new;
方法引用的通常語法是 Qualifier::MethodName
Function<Integer, String> func1 = x -> Integer.toBinaryString(x); Function<Integer, String> func2 = Integer::toBinaryString;
Supplier<Integer> supplier = () -> "www.w3cschool.cn".length(); Supplier<Integer> supplier1 = "www.w3cschool.cn"::length;
Function<String[],List<String>> asList = Arrays::<String>asList; System.out.println(asList.apply(new String[]{"a","b","c"}));