Java 8 API添加了一個(gè)新的抽象稱為流Stream直砂,可以讓你以一種聲明的方式處理數(shù)據(jù)。
Stream 使用一種類似用 SQL 語句從數(shù)據(jù)庫查詢數(shù)據(jù)的直觀方式來提供一種對 Java 集合運(yùn)算和表達(dá)的高階抽象静暂。
Stream API可以極大提高Java程序員的生產(chǎn)力洽蛀,讓程序員寫出高效率疟赊、干凈、簡潔的代碼驮审。
這種風(fēng)格將要處理的元素集合看作一種流椅挣, 流在管道中傳輸, 并且可以在管道的節(jié)點(diǎn)上進(jìn)行處理峡竣, 比如篩選, 排序适掰,聚合等。
元素流在管道中經(jīng)過中間操作(intermediate operation)的處理载城,最后由最終操作(terminal operation)得到前面處理的結(jié)果费就。
1.1 什么是 Stream?
Stream(流)是一個(gè)來自數(shù)據(jù)源的元素隊(duì)列并支持聚合操作
- 元素是特定類型的對象睬澡,形成一個(gè)隊(duì)列煞聪。 Java中的Stream并不會存儲元素逝慧,而是按需計(jì)算。
- 數(shù)據(jù)源流的來源云稚。 可以是集合碱鳞,數(shù)組,I/O channel, 產(chǎn)生器generator 等率拒。
- 聚合操作 類似SQL語句一樣的操作猬膨, 比如filter, map, reduce, find, match, sorted等呛伴。
和以前的Collection操作不同, Stream操作還有兩個(gè)基礎(chǔ)的特征:
- Pipelining: 中間操作都會返回流對象本身沛申。 這樣多個(gè)操作可以串聯(lián)成一個(gè)管道铁材, 如同流式風(fēng)格(fluent style)。 這樣做可以對操作進(jìn)行優(yōu)化村生, 比如延遲執(zhí)行(laziness)和短路( short-circuiting)饼丘。
- 內(nèi)部迭代: 以前對集合遍歷都是通過Iterator或者For-Each的方式, 顯式的在集合外部進(jìn)行迭代肄鸽, 這叫做外部迭代。 Stream提供了內(nèi)部迭代的方式贴捡, 通過訪問者模式(Visitor)實(shí)現(xiàn)烂斋。
1.2 生成流
在 Java 8 中, 集合接口有兩個(gè)方法來生成流:
- stream() ? 為集合創(chuàng)建串行流汛骂。
- parallelStream() ? 為集合創(chuàng)建并行流。
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
//解釋:過濾掉集合中不為空的數(shù)據(jù)帘瞭,然后輸出一個(gè)集合
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
1.3 Stream 提供的方法
1.3.1 forEach
Stream 提供了新的方法 'forEach' 來迭代流中的每個(gè)數(shù)據(jù)抛腕。以下代碼片段使用 forEach 輸出了10個(gè)隨機(jī)數(shù):
//生成10個(gè)隨機(jī)數(shù)媒殉,然后循環(huán)打印輸出
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
1.3.2 map
map 方法用于映射每個(gè)元素到對應(yīng)的結(jié)果,以下代碼片段使用 map 輸出了元素對應(yīng)的平方數(shù):
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 獲取對應(yīng)的平方數(shù)全封,然后去重刹悴,最后輸出一個(gè)集合
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
1.3.3 filter
filter 方法用于通過設(shè)置的條件過濾出元素攒暇。以下代碼片段使用 filter 方法過濾出空字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數(shù)量
int count = strings.stream().filter(string -> string.isEmpty()).count();
1.3.4 limit
limit 方法用于獲取指定數(shù)量的流扯饶。 以下代碼片段使用 limit 方法打印出 10 條數(shù)據(jù):
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
1.3.5 sorted
sorted 方法用于對流進(jìn)行排序池颈。以下代碼片段使用 sorted 方法對輸出的 10 個(gè)隨機(jī)數(shù)進(jìn)行排序:
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
1.3.6 并行(parallel)程序
parallelStream 是流并行處理程序的代替方法。以下實(shí)例我們使用 parallelStream 來輸出空字符串的數(shù)量:
List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 獲取空字符串的數(shù)量
int count = strings.parallelStream().filter(string -> string.isEmpty()).count();
我們可以很容易的在順序運(yùn)行和并行直接切換钓丰。
1.3.7 Collectors
Collectors 類實(shí)現(xiàn)了很多歸約操作躯砰,例如將流轉(zhuǎn)換成集合和聚合元素。Collectors 可用于返回列表或字符串:
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("篩選列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
1.3.8 統(tǒng)計(jì)
另外携丁,一些產(chǎn)生統(tǒng)計(jì)結(jié)果的收集器也非常有用琢歇。它們主要用于int、double梦鉴、long等基本類型上李茫,它們可以用來產(chǎn)生類似如下的統(tǒng)計(jì)結(jié)果。
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的數(shù) : " + stats.getMax());
System.out.println("列表中最小的數(shù) : " + stats.getMin());
System.out.println("所有數(shù)之和 : " + stats.getSum());
System.out.println("平均數(shù) : " + stats.getAverage());