java8的又一特性就是 流(Stream),流主要是對數(shù)據(jù)源(集合缠借、數(shù)組等)的一種處理方式干毅,有高效的聚合操作、大批量的數(shù)據(jù)處理泼返,同時也內(nèi)置了許多運(yùn)算方式硝逢,包括篩選、排序绅喉、聚合等 渠鸽,特別提醒:流運(yùn)用了大量的lambda表達(dá)式。 這里只是列出一些常用的知識點(diǎn)柴罐,幫助你快速了解它徽缚。
幾大特點(diǎn)
- 與lambda表達(dá)式結(jié)合,代碼極簡丽蝎,可讀性高
- 提供并行操作猎拨,充分發(fā)揮多核處理器優(yōu)勢
- 進(jìn)行并行操作,無需額外編寫多線程代碼即可實(shí)現(xiàn)高效并發(fā)程序屠阻,規(guī)避多線程代碼問題
簡單基本概念
- 元素 流Stream是來自數(shù)據(jù)源的元素隊(duì)列红省,本身不具備元素
- 數(shù)據(jù)源 包括包含集合、數(shù)組国觉、I/O channel吧恃、generator(發(fā)生器)等
- 聚合操作 類似SQL中的filter、map麻诀、find痕寓、match、sorted等操作
- 管道運(yùn)算 Stream在Pipeline中運(yùn)算后返回Stream對象本身蝇闭,這樣多個操作串聯(lián)成一個Pipeline呻率,并形成fluent風(fēng)格的代碼。這種方式可以優(yōu)化操作呻引,如延遲執(zhí)行(laziness)和短路( short-circuiting)礼仗。(我理解為鏈?zhǔn)讲僮?
- 內(nèi)部迭代 不同于java8以前對集合的遍歷方式(外部迭代),采用訪問者模式(Visitor)實(shí)現(xiàn)了內(nèi)部迭代逻悠。
- 并行運(yùn)算 Stream API支持串行(stream() )或并行(parallelStream() )的兩種操作方式元践。
簡單實(shí)例
- java8之前
public static void main(String[] args)
{
List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5);
long count = 0;
for(Integer number: numbers)
{
if(number > 0)
{
count++;
}
}
System.out.println("Positive count: " + count);
}
通常利用for循環(huán)遍歷
- java8之后
public static void main(String[] args)
{
List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5);
long count = numbers.parallelStream().filter(i -> i>0).count();
System.out.println("Positive count: " + count);
}
上例中,使用filter()
方法對數(shù)組進(jìn)行了過濾童谒,使用count()方法對過濾后的數(shù)組進(jìn)行了大小統(tǒng)計(jì)单旁,且使parallelStream()
方法為集合創(chuàng)建了并行流,自動采用并行運(yùn)算提高速度饥伊。在更復(fù)雜的場景象浑,還可以用forEach()蔫饰、map()、limit()融柬、sorted()死嗦、collect()
等方法進(jìn)行進(jìn)一步的流運(yùn)算。
并且 通常會和lambda表達(dá)式一起使用粒氧,使得代碼更加優(yōu)雅越除。
常用接口
- Stream的生成( 串行流 :
stream()
; 并行流 :parallelStream()
)
List list = new ArrayList();
list.stream().//接下來管道操作
- forEach()方法 (用來迭代流中的每一個數(shù)據(jù))
List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5);
numbers.stream().forEach(n -> System.out.println("List element: " + n));
- map()方法 (將流中的所有元素用Function對象進(jìn)行運(yùn)算外盯,生成新的流對象)
List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5);
numbers.stream().map( n -> Math.abs(n)).forEach(n -> System.out.println("Element abs: " + n));
- flatMap()方法 (比map()方法擁有更高的映射深度)
用flatMap()方法如下:
List<String> list = Arrays.asList("1 2", "3 4", "5 6");
list.stream().flatMap(item -> Arrays.stream(item.split(" "))).forEach(System.out::println);
而用map()方法:
List<String> list = Arrays.asList("1 2", "3 4", "5 6");
list.stream().map(item -> Arrays.stream(item.split(" "))).forEach(n ->n.forEach(System.out::println));
可見摘盆,用map()方法,返回了一個“流中流”饱苟,需要在每個Stream元素遍歷時孩擂,再加一層forEach進(jìn)行遍歷。
- filter()方法 (過濾)
List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5);
long count = numbers.parallelStream().filter(i -> i>0).count();
System.out.println("Positive count: " + count);
- reduce()方法 (為折疊操作箱熬,用于將流中的所有值合成一個)
List<Integer> numbers = Arrays.asList(-1, -2, 0, -1, 4, 5, 1);
Integer total = numbers.stream().reduce((t, n) -> t + n).get();
System.out.println("Total: " + total);
- collect()方法 (將流轉(zhuǎn)為數(shù)據(jù)源 (集合等))
collect()方法的參數(shù)為一個java.util.stream.Collector類型對象类垦,可以用java.util.stream.Collectors工具類提供的靜態(tài)方法來生成,Collectors類實(shí)現(xiàn)很多的歸約操作城须,如Collectors.toList()蚤认、Collectors.toSet()、Collectors.joining()(joining適用于字符串流)等
List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5);
List<Integer> abss = numbers.stream().map( n -> Math.abs(n)).collect(Collectors.toList());
System.out.println("Abs list: " + abss);
- 數(shù)值操作的方法
Stream采用mapToInt()糕伐、mapToLong()砰琢、mapToDouble()
三個方法分別生成IntStream 、LongStream 良瞧、DoubleStream 三個接口類型的對象
IntStream 陪汽、LongStream 、DoubleStream 三個接口類型都有一個summaryStatistics()方法褥蚯,其中挚冤,
IntStream 的方法是:IntSummaryStatistics summaryStatistics();
LongStream 的方法是:LongSummaryStatistics summaryStatistics();
DoubleStream 的方法是:DoubleSummaryStatistics summaryStatistics();
在IntSummaryStatistics、LongSummaryStatistics 赞庶、DoubleSummaryStatistics
三個接口類型(位于java.util包下)中训挡,都有諸如統(tǒng)計(jì)數(shù)量、最大值尘执、最小值、求和宴凉、平均值等方法(方法名和返回類型可能不同),可以方便的進(jìn)行數(shù)值統(tǒng)計(jì)誊锭。
看這么多文字,還是來個例子消化比較好:
List<Integer> numbers = Arrays.asList(-1, -2, 0, 4, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Max : " + stats.getMax());
System.out.println("Min : " + stats.getMin());
System.out.println("Sum : " + stats.getSum());
System.out.println("Average : " + stats.getAverage());
System.out.println("Count : " + stats.getCount());
- 其它方法
Stream API還有一些其它的方法弥锄,比如:
limit() 獲取指定數(shù)量的流
sorted() 對流進(jìn)行排序
distinct() 去重
skip() 跳過指定數(shù)量的元素
peek() 生成一個包含原Stream的所有元素的新Stream丧靡,并指定消費(fèi)函數(shù)
count() 計(jì)算元素?cái)?shù)量
這部分只是流stream的冰山一角蟆沫,想要深入的朋友可以去看下java8的關(guān)于流這部分的源碼,進(jìn)行深入學(xué)習(xí)温治。