Java 8中新增了函數——值的一種新形式。函數做爲一等值,使用方法引用 :: 語法(即「把這個方法做爲值」),做爲函數式值來傳遞。html
File[] hiddenFiles = new File(".").listFiles(new FileFilter() { public boolean accept(File file) { return file.isHidden(); } });
只要方法中有代碼(方法中的可執行部分),那麼用方法引用就能夠傳遞代碼。java
File[] hiddenFiles = new File(".").listFiles(File::isHidden);
除了容許(命名)函數成爲一等值外,Java 8還體現了更廣義的將函數做爲值的思想,包括Lambda(或匿名函數)。能夠把Lambda表達式理解爲簡潔地表示可傳遞的匿名函數的一種方式:它沒有名稱,但它有參數列表、函數主體、返回類型,可能還有一個能夠拋出的異常列表。express
Lambda表達式由參數、箭頭和主體組成。在函數式接口上使用Lambda表達式。app
函數式接口就是隻定義一個抽象方法的接口。函數
Lambda的基本語法是this
(parameters) -> expression
或(請注意語句的花括號)lua
(parameters) -> { statements; }
下面給出了Java 8中五個有效的Lambda表達式的例子。spa
// 1 (String s) -> s.length() // 2 (Apple a) -> a.getWeight() > 150 // 3 (int x, int y) -> { System.out.println("Result:"); System.out.println(x+y); } // 4 () -> 42 // 5 (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())
第一個Lambda表達式具備一個 String 類型的參數並返回一個 int 。Lambda沒有 return 語句,由於已經隱含了 return。設計
第二個Lambda表達式有一個Apple 類 型 的參數並返回一個 boolean (蘋果的重量是否超過150克)。code
第三個Lambda表達式具備兩個 int 類型的參數而沒有返回值( void 返回)。注意Lambda表達式能夠包含多行語句,這裏是兩行。
第四個Lambda表達式沒有參數,返回一個int 。
第五個Lambda表達式具備兩個 Apple 類型的參數,返回一個 int :比較兩個 Apple 的重量。
和Collection API相比,Stream API處理數據的方式很是不一樣。用集合的話,你得本身去作迭代的過程。你得用 for-each 循環一個個去迭代元素,而後再處理元素。咱們把這種數據迭代的方法稱爲外部迭代。相反,有了Stream API,你根本用不着操心循環的事情。數據處理徹底是在庫內部進行的。咱們把這種思想叫做內部迭代。
Collection主要是爲了存儲和訪問數據,而Stream則主要用於描述對數據的計算。這裏的關鍵點在於,Stream容許並提倡並行處理一個 Stream 中的元素。雖然可能乍看上去有點兒怪,但篩選一個 Collection 的最快方法經常是將其轉換爲 Stream ,進行並行處理,而後再轉換回 List 。
好比,利用Stream和Lambda表達式順序或並行地從一個列表裏篩選比較重的蘋果。
import static java.util.stream.Collectors.toList; List<Apple> inventory = Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")); List<Apple> apples = inventory.stream() .filter((Apple a) -> a.getWeight() > 150) .collect(toList()); // 並行處理 List<Apple> apples2 = inventory.parallelStream() .filter((Apple a) -> a.getWeight() > 150) .collect(toList());
filter方法傳入的參數實際上是謂詞,咱們來看下JDK8 Predicate類源碼。
package java.util.function; import java.util.Objects; /** * Represents a predicate (boolean-valued function) of one argument. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #test(Object)}. * * @param <T> the type of the input to the predicate * * @since 1.8 */ @FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); // ... }
什麼是謂詞?
謂詞(predicate)在數學上經常用來表明一個相似函數的東西,它接受一個參數值,並返回 true 或 false 。
filter經過行爲參數化進行代碼傳遞。行爲參數化,就是一個方法接受多個不一樣的行爲做爲參數,並在內部使用它們,完成不一樣行爲的能力。其實就是策略模式,它能夠把一個行爲(一段代碼)封裝起來,並經過傳遞和使用建立的行爲(例如不一樣謂詞)將方法的行爲參數化。行爲參數化可讓代碼更好地適應不斷變化的要求,減輕將來的工做量。
Java API中的不少方法均可以用不一樣的行爲來參數化(好比Comparator 排序,用 Runnable 執行一個代碼塊,以及GUI事件處理),這些方法每每與匿名類一塊兒使用。
Java 8中加入默認方法主要是爲了支持庫設計師,讓他們可以寫出更容易改進的接口。在接口中使用默認方法,在實現類沒有實現方法時提供方法內容。在接口聲明中使用新的 default 關鍵字來表示這一點。
書籍《Java 8實戰》