Java8中新增的特性中谈山,對(duì)核心類庫(kù)的改進(jìn)是很關(guān)鍵的一部分榛瓮,這部分主要包括了集合類的API和新引入的流(Stream),流使得我們可以站在更高的抽象層次上對(duì)集合進(jìn)行操作,下面我們就來熟悉一下什么是流爬橡。
Stream<String> stream1 = Stream.of("hello", "world", "hello world");
這樣就創(chuàng)建了一個(gè)流,如果我們要找到流中字符串長(zhǎng)度小于6的字符串個(gè)數(shù)友绝,我們可以這樣寫
long count = stream1.filter(item -> item.length() < 6).count();//2
可以看到我們用了兩步來求值
1.filter(item -> item.length() < 6)
過濾字符串長(zhǎng)度小于6
2.count()
計(jì)算數(shù)量
看起來像是進(jìn)行了兩次循環(huán)堤尾,其實(shí)不然
stream1.filter(item -> item.length() < 6)
這行代碼并未做什么實(shí)質(zhì)性的工作,只是描述了Stream迁客,我們可以測(cè)試一下
stream1.filter(item ->{
System.out.println("filter");
return item.length() < 6;
}
);
運(yùn)行程序郭宝,發(fā)現(xiàn)并沒有打印任何東西,我們繼續(xù)加上count看一下
stream1.filter(item ->{
System.out.println("filter");
return item.length() < 6;
}
).count();
這時(shí)打印出了
filter
filter
filter
之所以是這樣掷漱,是因?yàn)榱鞑僮鞣譃閮深悾?br>
1.惰性求值:返回一個(gè)Stream
2.及早求值:返回具體的值
一個(gè)流操作有三部分組成:
1.源
2.零個(gè)或多個(gè)中間操作
3.終止操作
在執(zhí)行終止操作前粘室,流中間的多個(gè)操作都不會(huì)運(yùn)行,只有當(dāng)執(zhí)行了終止操作后卜范,流才會(huì)根據(jù)所有的條件去綜合執(zhí)行衔统。
常用的流操作
- collect(toList())
collect(toList())是由Stream里的值生成一個(gè)列表,是一個(gè)及早求值操作海雪。
List<String> list = Stream.of("a", "b", "c").collect(Collectors.toList());
list.forEach(System.out::print);//abc
- map
將一個(gè)流中的值轉(zhuǎn)換成一個(gè)新的流
Java8之前如果我們要將一個(gè)列表中的字符串轉(zhuǎn)換成大寫锦爵,要這樣寫
List<String> newList = new ArrayList();
List<String> list = Arrays.asList("a", "b", "c");
for (String str : list) {
newList.add(str.toUpperCase());
}
newList.forEach(System.out::print);//ABC
使用map我們只需要這樣寫,map所接收的Lambda表達(dá)式必須是一個(gè)Function接口的一個(gè)實(shí)例奥裸。
List<String> list = Arrays.asList("a", "b", "c");
List<String> newList = list.stream().map(String::toUpperCase).collect(Collectors.toList());
newList.forEach(System.out::print);//ABC
在Stream中對(duì)原生類型的map操作進(jìn)行了幾個(gè)擴(kuò)展险掀,有mapToInt、mapToLong湾宙、mapToDouble樟氢,所以在進(jìn)行具體使用的時(shí)候最好具體指定具體類型的方法冈绊,這樣可以避免自動(dòng)裝箱拆箱帶來的損耗
Stream.iterate(1,item-> item+2).limit(6).filter(value -> value>200).mapToInt(value -> value * 2).skip(2).limit(2).min().ifPresent(System.out::print);
- filter
這個(gè)在最上面也講過了,filter接收的Lambda表達(dá)式必須是一個(gè)Predicate接口的一個(gè)實(shí)例。
Stream<String> stream1 = Stream.of("hello", "world", "hello world");
long count = stream1.filter(item -> item.length() < 6).count();
System.out.println(count);
- flatMap
flatMap方法可用Stream替換值埠啃,然后將多個(gè)Stream連接成一個(gè)Stream
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
假設(shè)有一個(gè)包含多個(gè)列表的流死宣,現(xiàn)在要得到所有數(shù)字的序列
Stream<List<Integer>> stream = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4), Arrays.asList(5, 6, 7));
List<Integer> list = stream.flatMap(item->item.stream()).collect(Collectors.toList());
System.out.println(list);//[1, 2, 3, 4, 5, 6, 7]
- max和min
求最大最小值是很常用的操作,方法接收一個(gè)Comparator對(duì)象碴开,Java8提供了一個(gè)新的靜態(tài)方法comparing毅该,該方法接收一個(gè)函數(shù),返回一個(gè)函數(shù)潦牛,max方法返回的是一個(gè)Optional對(duì)象
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.stream().max(Comparator.comparing(item -> item)).ifPresent(System.out::println);//7
6.reduce
max和min都屬于一種通用的編程模式鹃骂,這種模式可以用以下偽代碼體現(xiàn):
Object accumulator = initialValue;
for(Object element : collection){
accumulator = combine(accumulator,element);
}
首先賦給accumulator一個(gè)初始值:initialValue,然后在循環(huán)體中罢绽,通過調(diào)用combine函數(shù),拿accumulator和集合中的每一個(gè)元素做運(yùn)算静盅,再將運(yùn)算結(jié)果賦給accumulator良价,最后accumulator的值就是想要的結(jié)果。
上面例子中用到的count蒿叠、max明垢、min方法,其實(shí)都是reduce操作市咽,因?yàn)槌S盟员患{入標(biāo)準(zhǔn)庫(kù)中痊银。
來看幾個(gè)例子
求和:
int count = Arrays.asList(1, 2, 3).stream().reduce(0,(acc,item)->acc+item);
System.out.println(count);//6
求最大值:
List<Integer> list2 = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list2.stream().reduce((maxitem,item)->{
System.out.println("maxitem:"+maxitem + "item:"+item);
if(maxitem < item){
return item;
}else{
return maxitem;
}
}).ifPresent(System.out::println);//7
log打印:
maxitem:1item:2
maxitem:2item:3
maxitem:3item:4
maxitem:4item:5
maxitem:5item:6
maxitem:6item:7
可以看出reduce執(zhí)行的邏輯施绎,上面程序是為了看內(nèi)部實(shí)現(xiàn)溯革,其實(shí)可以簡(jiǎn)短的寫成
list2.stream().reduce(BinaryOperator.maxBy(Comparator.comparingInt(Integer::new))).ifPresent(System.out::println);
總結(jié)
本次主要介紹了Stream的基本概念以及用法,作為一個(gè)初步了解谷醉,關(guān)于Stream還有著更加復(fù)雜的操作以及一些陷阱致稀,后續(xù)我們?cè)僦鸩椒治觥?/p>