第一章 Lambda表達式
Lamada 表達式是Java SE 8中最重要的新特性,長期以來被認為是在Java中缺失的特性,它的出現使整個java 語言變得完整。至少到目前,在這節中你將學習到什么是lambda,為什么他是出色的一部分。同時也會介紹一些新的技術例如單一抽象方法和函數式接口。
為什么是lambda 表達式。
就像閉包一樣, Lambda表達會使一些結構變得精簡和良好的可讀性,特別是在有處理內部類的時候。下面的例子是用內部類實現的代碼塊:
Runnable runnable = new Runnable() {
@Override
public void run() {
|
在Java核心庫中常見的函數式接口有:java.lang.Runnable,java.lang.AutoCloseable,java.lang.Comparable,java.util.Comparator.此外,在java.util.function也有很多。
函數式接口可以用注解@FunctionalInterface標注。
為什么函數式接口這么重要?你可以使用函數式接口替代匿名內部類。如果不是,則不能這么用。
lambda 表達式語法
在上面的例子中calculate方法可以看作最基本的 lambda表達式語法。這個方法允許你定義任何的數學計算,使用兩個整形參數返回一個double類型。下面有兩個例子。
Calculator addition = (int a, int b) -> (a + b);System.out.println(addition.calculate(5, 20)); // prints 25.0Calculator division = (int a, int b) -> (double) a / b;System.out.println(division.calculate(5, 2)); // prints 2.5 |
Lambda表達式就是這么優雅,要是沒有它你該多寫多少代碼?
Lambda表達式的標準定義有兩種:
(parameter list) ->expression
或
(parameter list) -> {statements}參數的類型跟接口中抽象方法的參數是一致的。不過,參數類型是可選的。換句話說,下面的方法是有效的。Calculator addition = (int a, int b) -> (a + b);Calculator addition = (a, b) -> (a + b);總結一下,Lambda表達式就是函數是接口實現的快捷方式,它相當于函數式接口實現的實例,因為在方法中可以使用Object作為參數,所以把Lambda表達式作為方法的參數也是可能的。Java中預定義的函數式接口java.util.function是java 8 中一個新包,里面包含了超過40個預定義函數式接口方便你去書寫 Lambda 表達式風格的代碼。下面是一些常用的接口。
| 函數式接口 | 描述 |
| Function | 傳遞一個參數返回一個結果。這個結果的類型可以與參數的類型不相同。 |
| BiFunction | 傳遞兩個參數返回一個結果。這個結果的類型可以與任一參數的類型不相同。 |
| UnaryOperator | 代表一個操作符的操作,它的返回結果類型與操作符的類型一樣。實際上它可以被看作是Function 它的返回結果跟參數一樣,它是Function 的子接口。 |
| BiOperator | 代表兩個操作符的操作,它的返回結果類型必須與操作符相同。 |
| Predicate | 傳遞一個參數,基于參數的值返回boolean值。 |
| Supplier | 代表一個供應者的結果。 |
| Consumer | 傳遞一個參數但沒有返回值。 |
Function, BiFunction and Other VariantsFunction接口通常用來創建一個參數的函數并返回一個結果。它是參數化的類型,定義如下:public interface Function<T, R>T是參數類型,R是返回的結果類型。Function只有一個抽象方法,apply,它的簽名如下:R apply(Targument)這個方法需要重寫當使用Function的時候,下面的例子定義了一個Function用來實現英米與公里的轉換。Function傳遞一個Integer類型作為參數,并返回Double類型。
} |
執行此類,在控制臺輸出:3 miles = 4.80 kilometersBiFunction是Function的一種變體,它傳遞兩個參數并返回一個結果,下面的例子創建一個Function 根據給定的長和寬計算面積,需要調用apply方法實現。import java.util.function.BiFunction;public class BiFunctionDemo1 { public static void main(String[] args) { BiFunction<Float, Float, Float> area = (width, length) -> width * length; float width = 7.0F; float length = 10.0F; float result = area.apply(width, length); System.out.println(result); }} |
控制臺輸出:70.0 |
除了BiFunction,還有一系列的Function變體,例如,IntFunction 只能傳遞int類型的參數。LongFunction and DoubleFunction 與IntFunction用法類似,只是傳遞的參數類型不同。還有一些變體不要求傳遞參數化的參數,因為他們被設計成傳遞制定類型參數,并返回制定類型的結果。例如,IntToDoubleFunction 接受int類型參數并返回double類型結果,還有區別是,使用applyAsDouble 替代apply方法,下面的例子實現攝氏溫度轉換成華氏溫度。
import java.util.function.IntToDoubleFunction;public class IntToDoubleFunctionDemo1 { public static void main(String[] args) { IntToDoubleFunction celciusToFahrenheit = (input) -> 1.8 * input + 32; int celcius = 100; double fahrenheit = celciusToFahrenheit.applyAsDouble(celcius); System.out.println(celcius + "/u2103" + " = " + fahrenheit + "/u2109/n"); }} |
控制臺輸出:100℃ = 212.0℉LongToDoubleFunction and LongToIntFunction 用法與IntToDoubleFunction類似。UnaryOperator 是 Function 的另一種特殊實現,他的操作符類型與返回類型一樣。它的定義如下: public interfaceUnaryOperator<T> extends Function<T,T>BinaryOperator 是 BiFunction 的一特殊實現,要求所有參數類型一樣并與返回類型一樣。
Predicate
Predicate是根據傳遞參數的值返回boolean值。它有一個抽象方法test。
舉例,下面的PredicateDemo1 類 定義一個Predicate 來判斷傳遞進去的字符串每一個字符是否全是數字。
1 import java.util.function.Predicate; 2 3 public class PredicateDemo1 { 4 public static void main(String[] args) { 5 Predicate<String> numbersOnly = (input) -> { 6 for (int i = 0; i < input.length(); i++) { 7 char c = input.charAt(i); 8 if ("0123456789".indexOf(c) == -1) { 9 return false;10 }11 }12 return true;13 };14 15 System.out.println(numbersOnly.test("12345"));// true16 System.out.println(numbersOnly.test("100a")); // false17 }18 }Supplier
Supplier沒有參數但返回一個值。要實現這個接口必須重寫get抽象方法并返回參數化類型的實例。
下面的例子,Supplier定義了一個返回 數字隨機數,并使用for循環打印5個隨機數。
import java.security.SecureRandom;import java.util.function.Supplier;public class SupplierDemo1 { public static void main(String[] args) { Supplier<Integer> oneDigitRandom = () -> { SecureRandom random = new SecureRandom(); return random.nextInt(10); }; for (int i = 0; i < 5; i++) { System.out.println(oneDigitRandom.get()); } }}還有一些Supplier的變體,例如DoubleSupplier (返回 Double), IntSupplier 和LongSupplier.
Consumer
Consumer是一個沒有返回值的操作,它有一個抽象方法accept。
下面的例子使用ConSumer傳遞一個字符串參數,根據字符串的長度,和使用Function返回的空格的長度,最后把空格與字符串連接。
1 import java.util.function.Consumer; 2 import java.util.function.Function; 3 4 public class ConsumerDemo1 { 5 public static void main(String[] args) { 6 Function<Integer, String> spacer = (count) -> { 7 StringBuilder sb = new StringBuilder(count); 8 for (int i = 0; i < count; i++) { 9 sb.append(" ");10 }11 return sb.toString();12 };13 14 int lineLength = 60; // characters15 Consumer<String> printCentered = (input) -> {16 int length = input.length();17 String spaces = spacer.apply((lineLength - length) / 2);18 System.out.println(spaces + input);19 };20 21 printCentered.accept("A lambda expression a day");22 printCentered.accept("makes you");23 printCentered.accept("look smarter");24 }25 }
|
新聞熱點
疑難解答