一、簡介
html
Java 8是Java自Java 5(發佈於2004年)以後的最重要的版本。這個版本包含語言、編譯器、庫、工具和JVM等方面的十多個新特性。在本文中咱們一塊兒來學習引入的一個新特性-流java
二、Lambda表達式數組
在學習流以前,咱們先來了解下java8中引入的Lambda表達式,它做爲流很重要的一部分。Lambda表達式個構成以下所示:oracle
2.1 有效的Lambda表達式app
()-> 42 (Apple a) -> { return a.getWeight() > 150; } //對於函數只有一行代碼的,能夠去掉大括號{}以及return關鍵字 (String s)-> s.length() (Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight())
2.2 方法引用
函數
當你須要使用方法引用時,目標放在分隔符::前,方法的名稱放在後面。例如:Apple::getWeight就是引用了Apple類中定義的方法getWeight。請記住,不須要括號,由於你工具
沒有實際調用這個方法。方法引用就是Lambda表達式(Apple a) -> a.getWeight的快捷寫法。學習
Lambda及其等效方法引用的列子:spa
方法引用主要有三類:.net
第二種和第三種方法引用可能乍看起來有點兒暈。相似於String::length的第二種方法引用的思想就是你在引用一個對象的方法,而這個對象自己是Lambda的一個參數。例如,Lambda表達
式(String s) -> s.toUppeCase()能夠寫做String::toUpperCase。但第三種方法引用指的是,你在Lambda中調用一個已經存在的外部對象中的方法。例如,Lambda表達式()->expensiveTransaction.getValue()可
以寫做expensiveTransaction::getValue。
2.3 構造函數引用
Supplier<Apple> c1 = Apple::new; // 構造函數引用指向默認的Apple()構造函數 Apple apple = c1.get(); // 調用Supplier的get方法將產生一個新的Apple Function<Integer, Apple> c2 = Apple::new; // 指向Apple(Integer weight)的構造函數引用 Apple apple2 = c2.apply(110); // 調用該Function函數的apply方法,並給出要求的重量,將產生一個Apple
在下面的代碼中,一個Integer構成的List中的每一個元素都經過咱們前面定義的類的map方法傳遞給了Apple的構造函數,獲得了一個具備不一樣重量蘋果的List:
private static void test() { List<Integer> weights = Arrays.asList(7, 3, 4, 10); List<Apple> apples = map(weights, Apple::new); apples.stream().map(Apple::getWeight).forEach(System.out::println); } public static List<Apple> map(List<Integer> list, Function<Integer, Apple> f) { List<Apple> result = new ArrayList<>(); for (Integer e : list) { result.add(f.apply(e)); } return result; }
三、引入流
3.1流簡介
流是一系列數據項,一次只生成一項。程序能夠從輸入流中一個一個讀取數據項,而後以一樣的方式將數據項寫入輸出流。一個程序的輸出流極可能是另外一個程序的輸入流。就想汽車組裝流水線一
樣,汽車排隊進入加工站,每一個加工站會接收、修改汽車,而後將之傳遞給下一站作進一步的處理。儘管流水線其實是一個序列,但不一樣加工站的運行通常是並行的。
基於此,Java8能夠透明的把輸入的不想管部分拿到幾個CPU內核上去分別執行你的Stream操做流水線——這是幾乎免費的並行,用不着費勁搞Thread了。
3.2流操做
流操做包含3個部分:數據源、中間操做、終端操做
數據源:集合、數組
中間操做:能夠鏈接起來的流操做,流程一條流水線
終端操做:關閉流的操做
中間操做和終端操做,以下圖所示:
3.3 使用流
篩選和切片:filter()、distinct()、limit()、skip()
映射:map()
查找和匹配:anyMatch()、allMatch()、noneMatch()、findAny()、findFirst()
歸約:reduce()
3.3.1 篩選和切片
filter():篩選過濾。會接受一個謂詞(一個返回boolean的函數)做爲參數,並返回一個包括全部符合謂詞的元素的流。
distinct():去重。它會返回一個元素各異(根據流所生成元素的hashCode和equals方法實現)的流
limit(n):截斷。它會返回一個不超過給定長度的流,若是流是有序的,則最多返回前n個元素
skip(n):跳過。返回一個扔掉了前n個元素的流
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4,5, 6); numbers.stream() .filter(i -> i % 2 == 0) //篩選出能被2整除的 .distinct() //去重 .limit(3) //取前3個元素 .skip(1) //扔掉第一個元素 .forEach(System.out::println);
3.3.2 映射
map():映射。它會接受一個函數做爲參數。這個函數會被應用到每一個元素上,並將其映射成一個新的元素
例如,下面的代碼,提取菜單中菜的名字
List<String> nameList = menu.stream()
.map(Dish::getName)
.collect(Collectors.toList())
3.3.4 查找和匹配
anyMatch():流中是否有一個元素能匹配給定的謂詞
List<Integer> numbers = Arrays.asList(6, 5, 4, 8, 1, 2, 3, 4, 2, 5, 6, 8, 10); numbers.stream().anyMatch(d -> d % 3 == 0) ; //true
allMatch():流中的元素是否都能匹配給定的謂詞
numbers.stream().allMatch(d -> d % 3 == 0); //false
noneMatch():與allMatch()相對,流中沒有任何元素與給定的謂詞匹配
numbers.stream().noneMatch(d -> d % 7 == 0); //true
findAny():返回當前流中的任意元素。不過該方法返回的是Optional<T>容器類,其方法包括
一、isPresent() 將在Optional包含值的時候返回true,否者返回false
二、T get() 會在值存在時返回值,不然拋出一個NoSuchElement異常
Optional<Integer> nums = numbers.stream().filter(d -> d % 4 == 0).findAny(); nums.isPresent(); //true nums.get(); //4
findFirst():找到第一個元素,工做方式相似於findAny()
3.3.5 歸約
把一個流中的元素組合起來,使用reduce操做來表達更復雜的查詢,好比「計算菜單中的總卡路里」或「菜單中卡路里最高的菜是哪個」。此類查詢須要將流中全部元素反覆結合起來,得
到一個值,好比一個Integer。這樣的查詢能夠被歸類爲歸約操做(將流歸約成一個值)
元素累加、累乘
List<Integer> numbers = Arrays.asList(4, 5, 3, 9); //有初始值: numbers.stream().reduce(0, (a, b) -> a + b); //21 numbers.stream().reduce(0, Integer::sum); //21 numbers.stream().reduce(1, (a, b) -> a * b); //540 //無初始值: Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b)); //對於無初始值的歸約,reduce操做沒法返回其和,只能將結果包裹在一個Optional對象裏,以代表可能不存在 sum.get(); //21
最大值、最小值
List<Integer> numbers = Arrays.asList(4, 5, 3, 9); Optional<Integer> max = numbers.stream().reduce(Integer::max); //最大值 max.get(); //9 Optional<Integer> min = numbers.stream().reduce(Integer::min); //最小值 min.get(); //3
求和、平均數
int total = menu.stream().collect(Collectors.summingInt(Dish::getCalories)); //統計總數 double avg = menu.stream().collect(Collectors.averagingInt(Dish::getCalories)); // 求平均數 long count = menu.stream().count(); //個數 IntSummaryStatistics summ = menu.stream().collect(Collectors.summarizingInt(Dish::getCalories)); summ.getAverage(); //平均數 summ.getCount(); //個數 summ.getMax(); //最大值 summ.getMin(); //最小值 summ.getSum(); //和
3.4 用流收集數據
收集器(collect):是一個將數據流縮減爲一個值的高級歸約操做,這個值能夠是集合、映射、或者一個值對象。你可使用collect達到如下目的:
一、將數據流縮減爲一個單一值
二、將一個數據流中的元素進行分組
三、分割一個流中的元素
public List<String> getList(List<Task> tasks) { //將數據收集進一個列表 return tasks.stream().map(Task::getTitle).collect(Collectors.toList()); } public Set<String> getSet(List<Task> tasks) { //將數據收集進一個集合 return tasks.stream().map(Task::getTitle).collect(Collectors.toSet()); } private static Map<String, Task> taskMap(List<Task> tasks) { //將數據收集進一個映射 return tasks.stream().collect(Collectors.toMap(Task::getTitle, task -> task)); } private static Map<TaskType, List<Task>> groupTasksByType(List<Task> tasks) { //分組 return tasks.stream().collect(Collectors.groupingBy(Task::getType)); }
其它參照資源:http://blog.csdn.net/u013291394/article/details/52662761