如果前方的路是黑暗的,那應(yīng)該先找到指路的燈
java8中的 StreamAPI 非常豐富,本文介紹幾種比較重要的API。
- collect(toList()) 這個(gè)方法是用于生成一個(gè)列表, 是一個(gè)
及早求值操作.
下面看一段示例代碼
List<String> collected = Stream.of("a", "b", "c").
collect(Collectors.toList());
assertEquals(Arrays.asList("a", "b", "c"), collected);
上一篇文章中說(shuō)過(guò),Stream中的很多操作都是惰性求值,因此在Stream中的一系列方法之后,需要調(diào)用一個(gè)collect的及早求值方法,從而得到一個(gè)List<String>,下面這句是用斷言測(cè)試工具測(cè)試結(jié)果是否為預(yù)期的。
- map操作可以將一個(gè)流中的值轉(zhuǎn)換成一個(gè)新的流
下面看一段示例代碼
//使用map操作
List<String> collected = Stream.of("a", "b", "hello")
.map(str -> str.toUpperCase()).collect(Collectors.toList());
assertEquals(Arrays.asList("A", "B", "HELLO"), collected);
傳給map的lambda表達(dá)式只接受一個(gè)String類(lèi)型的參數(shù),返回一個(gè)新的String。參數(shù)和返回值不必屬于同一種類(lèi)型,但是lambda表達(dá)式必須是Function接口的一個(gè)實(shí)例,F(xiàn)unction接口是只包含一個(gè)參數(shù)的普通函數(shù)接口。
map操作一開(kāi)始理解起來(lái)有點(diǎn)抽象。 在看看下面這個(gè)例子
//使用map操作
List<Integer> collected2 = Stream.of(1, 2, 3).map(i32 -> i32 + 1)
.collect(Collectors.toList());
collected2.stream().forEach(i32 -> {
System.out.println(i32);
});
assertEquals(Arrays.asList(2, 3, 4), collected2);
這里通過(guò)實(shí)現(xiàn)map中的 Function接口,來(lái)對(duì)數(shù)據(jù)進(jìn)行 +1 的操作。
3.filter 遍歷數(shù)據(jù)并檢查其中的元素。
//使用filter操作
List<String> beginningWithNumbers = Stream.of("a", "abc", "1abc").
filter(value -> isDigit(value.charAt(0))).collect(Collectors.toList());
assertEquals(Arrays.asList("1abc"), beginningWithNumbers);
和map很像, filter接收一個(gè)函數(shù)作為參數(shù),該函數(shù)用lambda表達(dá)式表示。該函數(shù)和前面實(shí)例中if條件判斷語(yǔ)句的功能一樣,如果字符串首字母為數(shù)字,則返回true,因此若要重構(gòu)遺留的代碼,for循環(huán)中的if條件語(yǔ)句就可以用filter方法替代。
- flatMap
前面的map操作,它可用一個(gè)新的值代替Stream中的值,但有時(shí),用戶希望讓map操作有點(diǎn)變化,生成一個(gè)新的Stream對(duì)象代替它,但是又不希望結(jié)果是一連串的流,此時(shí)flatMap最能派上用場(chǎng)。 看下面的例子。
//使用flatMap
List<Integer> together = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4))
.flatMap(numbers -> numbers.stream()).
collect(Collectors.toList());
assertEquals(Arrays.asList(1, 2, 3, 4), together);
用flatMap實(shí)際上是將每個(gè)列表轉(zhuǎn)換成 Stream對(duì)象,其余部分由flatMap方法處理。flatMap方法相關(guān)函數(shù)接口和map方法一樣, 都是 Function接口,只是方法的返回值限定為Stream類(lèi)型了。通俗一點(diǎn)的講,就是將參數(shù)都轉(zhuǎn)換成stream,形成了一個(gè)stream在通過(guò)及早求執(zhí)方法 collect()得到一個(gè) together的 List<Integer>
- max 和 min操作。
max和min是Stream上比較常用的操作。例如下代碼中,找到track中字段num值最小的一條
List<Track> tracks = Arrays.asList(
new Track("第二天堂", 15),
new Track("大將軍", 8),
new Track("荒野獵人", 20));
Track shortestTrack = tracks.stream()
.min(Comparator.comparing(track -> track.getNum())).get();
assertEquals(tracks.get(1), shortestTrack);
max或min方法需要指定一個(gè)排序指標(biāo)作為甄選依據(jù),示例代碼中我們指定了num字段作為排序依據(jù),同理,需要獲取最大值時(shí),只需要改用max方法即可。為了讓Stream對(duì)象按照track的長(zhǎng)度進(jìn)行排序,需要傳一個(gè)Comparator對(duì)象,java8 中提供了一個(gè)新的靜態(tài)方法, comparing,使用它可以方便地實(shí)現(xiàn)一個(gè)比較器。
6.reduce操作
reduce操作可以實(shí)現(xiàn)從一組值中生成一個(gè)值,實(shí)際上 count ,max,min等因?yàn)楸容^常用,所以被納入了標(biāo)準(zhǔn)庫(kù)中,其實(shí)這些方法都是reduce操作,先看一段代碼
//點(diǎn)定義一個(gè) BinaryOperator并指定它的結(jié)果是由 第一個(gè)參數(shù)+第二個(gè)參數(shù)組成的
BinaryOperator<Integer> accumulator = (acc, element) -> acc + element;
//緊接著,模擬每一次的操作
int count2 = accumulator.
apply(accumulator.
apply(accumulator.
apply(0, 1)
, 2)
, 3);
這里先從最內(nèi)部開(kāi)始,第一個(gè)值 0,1相加得到1,第二層 1,2 相加得到3 ,最外面一層,3加3等于6,實(shí)際上,他的操作方式就是我們?cè)谏厦娲a第一行定義的。 然后改成使用reduce方式在看看代碼是怎么實(shí)現(xiàn)的呢?
int count = Stream.of(1, 2, 3).reduce(0, (acc, element) -> acc + element);
在使用Stream的reduce操作時(shí),實(shí)際上就是將集合中的參數(shù),以0為起點(diǎn),按照兩個(gè)參數(shù)傳入Stream中的當(dāng)前元素和 acc。將兩個(gè)參數(shù)相加,acc在這里實(shí)際上就是累加器,保存著當(dāng)前的累加結(jié)果。
此類(lèi)的計(jì)算方式,在引入java8之前,我們還需要使用for循環(huán),另外定義一個(gè)累加器,每次循環(huán)取出數(shù)據(jù)進(jìn)行累加,并更新打累加器。 如果使用了reduce方式,是不是方便了很多呢。
其實(shí)我們也可以通過(guò)reduce來(lái)實(shí)現(xiàn)諸如 max, min的方法
int max = Stream.of(1,2,3).reduce(0, (acc, element) -> acc>element?acc:element);
System.out.println(max);
int min = Stream.of(1, 2, 3).reduce(0, (acc, element) -> acc<element?acc:element);
System.out.println(min);
你值得擁有最好的自己