Java 8 Stream 閃亮登場!

Java技術(shù)棧
www.javastack.cn
關(guān)注閱讀更多優(yōu)質(zhì)文章
作者:funnyZpC
出處:cnblogs.com/funnyzpc/p/10382053.html
一. Stream(流)是什么,干什么
Stream是一類用于替代對集合操作的工具類+Lambda式編程,他可以替代現(xiàn)有的遍歷、過濾、求和、求最值、排序、轉(zhuǎn)換等
二. Stream操作方式
并行方式parallelStream
順序方式Stream
三. Stream優(yōu)勢
Lambda 可有效減少冗余代碼,減少開發(fā)工作量
內(nèi)置對集合List、Map的多種操作方式,含基本數(shù)據(jù)類型處理
并行Stream有效率優(yōu)勢(內(nèi)置多線程)
四. Stream(流)的基本使用
遍歷forEach
@Test
public?void?stream()?{
????//操作List
????List過濾filter
List?mapList?=?new?ArrayList()?{
{
????add(1);
????add(10);
????add(12);
????add(33);
????add(99);
}
};
//mapList.stream().forEach(item->?System.out.println(item));
mapList?=?mapList.stream().filter(item->{
return?item>30;
}).collect(Collectors.toList());
System.out.println(mapList);
轉(zhuǎn)換map和極值
@Test
public?void?trans(){
????List?ps?=?new?ArrayList(){
????????{
????????????Person?p1?=?new?Person();
????????????p1.setAge(11);
????????????p1.setName("張強");
????????????Person?p2?=?new?Person();
????????????p2.setAge(17);
????????????p2.setName("李思");
????????????Person?p3?=?new?Person();
????????????p3.setAge(20);
????????????p3.setName("John");
????????????add(p1);
????????????add(p2);
????????????add(p3);
????????}
????};
????
????//取出所有age字段為一個List
????List?sumAge?=?ps.stream().map(Person::getAge).collect(Collectors.toList());
????System.out.println(sumAge);
????
????//取出age最大的那
????Integer?maxAge?=sumAge.stream().max(Integer::compare).get();
????System.out.println(maxAge);
}
class?Person{
????private?String?name;
????private?Integer?age;
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?Integer?getAge()?{
????????return?age;
????}
????public?void?setAge(Integer?age)?{
????????this.age?=?age;
????}
}
五. Stream(流)的效率+ 模擬非耗時簡單業(yè)務(wù)邏輯
class?Person{
????private?String?name;
????private?int?age;
????private?Date?joinDate;
????private?String?label;
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?int?getAge()?{
????????return?age;
????}
????public?void?setAge(int?age)?{
????????this.age?=?age;
????}
????public?Date?getJoinDate()?{
????????return?joinDate;
????}
????public?void?setJoinDate(Date?joinDate)?{
????????this.joinDate?=?joinDate;
????}
????public?String?getLabel()?{
????????return?label;
????}
????public?void?setLabel(String?label)?{
????????this.label?=?label;
????}
}
public?class?DataLoopTest?{
????private?static?final?Logger?LOG=?LoggerFactory.getLogger(DataLoopTest.class);
????private?static?final?List?persons?=?new?ArrayList<>();
????static?{
????????for(int?i=0;i<=1000000;i++){
????????????Person?p?=?new?Person();
????????????p.setAge(i);
????????????p.setName("zhangSan");
????????????p.setJoinDate(new?Date());
????????????persons.add(p);
????????}
????}
????/**
?????*?for?循環(huán)耗時?===>?1.988
?????*?for?循環(huán)耗時?===>?2.198
?????*?for?循環(huán)耗時?===>?1.978
?????*
?????*/
????@Test
????public?void?forTest(){
????????Instant?date_start?=?Instant.now();
????????int?personSize?=?persons.size();
????????for(int?i=0;i????????????persons.get(i).setLabel(persons.get(i).getName().concat("-"+persons.get(i).getAge()).concat("-"+persons.get(i).getJoinDate().getTime()));
????????}
????????Instant?date_end?=?Instant.now();
????????LOG.info("for?循環(huán)耗時?===>?{}",?Duration.between(date_start,date_end).toMillis()/1000.0);
????}
????/**
?????*??forEach?循環(huán)耗時?===>?1.607
?????*??forEach?循環(huán)耗時?===>?2.242
?????*??forEach?循環(huán)耗時?===>?1.875
?????*/
????@Test
????public?void?forEach(){
????????Instant?date_start?=?Instant.now();
????????for(Person?p:persons){
????????????p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
????????}
????????Instant?date_end?=?Instant.now();
????????LOG.info("forEach?循環(huán)耗時?===>?{}",?Duration.between(date_start,date_end).toMillis()/1000.0);
????}
????/**
?????*??streamForeach?循環(huán)耗時?===>?1.972
?????*??streamForeach?循環(huán)耗時?===>?1.969
?????*??streamForeach?循環(huán)耗時?===>?2.125
?????*/
????@Test
????public?void?streamForeach(){
????????Instant?date_start?=?Instant.now();
????????persons.stream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
????????Instant?date_end?=?Instant.now();
????????LOG.info("streamForeach?循環(huán)耗時?===>?{}",?Duration.between(date_start,date_end).toMillis()/1000.0);
????}
????/**
?????*??parallelStreamForeach?循環(huán)耗時?===>?1.897
?????*??parallelStreamForeach?循環(huán)耗時?===>?1.942
?????*??parallelStreamForeach?循環(huán)耗時?===>?1.642
?????*/
????@Test
????public?void?parallelStreamForeach(){
????????Instant?date_start?=?Instant.now();
????????persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
????????Instant?date_end?=?Instant.now();
????????LOG.info("parallelStreamForeach?循環(huán)耗時?===>?{}",?Duration.between(date_start,date_end).toMillis()/1000.0);
????}
}
模擬耗時簡單業(yè)務(wù)邏輯
public?class?DataLoopBlockTest?{
????private?static?final?Logger?LOG=?LoggerFactory.getLogger(DataLoopTest.class);
????private?static?final?List?persons?=?new?ArrayList<>();
????static?{
????????for(int?i=0;i<=100000;i++){
????????????Person?p?=?new?Person();
????????????p.setAge(i);
????????????p.setName("zhangSan");
????????????p.setJoinDate(new?Date());
????????????persons.add(p);
????????}
????}
????/**
?????*?for?循環(huán)耗時?===>?101.385
?????*?for?循環(huán)耗時?===>?102.161
?????*?for?循環(huán)耗時?===>?101.472
?????*
?????*/
????@Test
????public?void?forTest(){
????????Instant?date_start?=?Instant.now();
????????int?personSize?=?persons.size();
????????for(int?i=0;i????????????try?{
????????????????Thread.sleep(1);
????????????????persons.get(i).setLabel(persons.get(i).getName().concat("-"+persons.get(i).getAge()).concat("-"+persons.get(i).getJoinDate().getTime()));
????????????}catch?(Exception?e){
????????????????e.printStackTrace();
????????????}
????????}
????????Instant?date_end?=?Instant.now();
????????LOG.info("for?循環(huán)耗時?===>?{}",?Duration.between(date_start,date_end).toMillis()/1000.0);
????}
????/**
?????*??forEach?循環(huán)耗時?===>?101.027
?????*??forEach?循環(huán)耗時?===>?102.488
?????*??forEach?循環(huán)耗時?===>?101.608
?????*/
????@Test
????public?void?forEach(){
????????Instant?date_start?=?Instant.now();
????????for(Person?p:persons){
????????????try?{
????????????????Thread.sleep(1);
????????????????p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
????????????}catch?(Exception?e){
????????????????e.printStackTrace();
????????????}
????????}
????????Instant?date_end?=?Instant.now();
????????LOG.info("forEach?循環(huán)耗時?===>?{}",?Duration.between(date_start,date_end).toMillis()/1000.0);
????}
????/**
?????*??streamForeach?循環(huán)耗時?===>?103.246
?????*??streamForeach?循環(huán)耗時?===>?101.128
?????*??streamForeach?循環(huán)耗時?===>?102.615
?????*/
????@Test
????public?void?streamForeach(){
????????Instant?date_start?=?Instant.now();
????????//persons.stream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
????????persons.stream().forEach(p->{
????????????try?{
????????????????Thread.sleep(1);
????????????????p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
????????????}catch?(Exception?e){
????????????????e.printStackTrace();
????????????}
????????});
????????Instant?date_end?=?Instant.now();
????????LOG.info("streamForeach?循環(huán)耗時?===>?{}",?Duration.between(date_start,date_end).toMillis()/1000.0);
????}
????/**
?????*??parallelStreamForeach?循環(huán)耗時?===>?51.391
?????*??parallelStreamForeach?循環(huán)耗時?===>?53.509
?????*??parallelStreamForeach?循環(huán)耗時?===>?50.831
?????*/
????@Test
????public?void?parallelStreamForeach(){
????????Instant?date_start?=?Instant.now();
????????//persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
????????persons.parallelStream().forEach(p->{
????????????try?{
????????????????Thread.sleep(1);
????????????????p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
????????????}catch?(Exception?e){
????????????????e.printStackTrace();
????????????}
????????});
????????Instant?date_end?=?Instant.now();
????????LOG.info("parallelStreamForeach?循環(huán)耗時?===>?{}",?Duration.between(date_start,date_end).toMillis()/1000.0);
????????//LOG.info("\r\n===>?{}",JSON.toJSONString(persons.get(10000)));
????}
}
可以看到在百萬數(shù)據(jù)下做簡單數(shù)據(jù)循環(huán)處理,對于普通for(for\foreach)循環(huán)或Stream(并行、非并行)下,幾者的效率差異并不明顯。
注意: 在百萬數(shù)據(jù)下,普通for、foreach循環(huán)處理可能比Stream的方式快許多,對于這點效率的損耗,其實lambda表達式對代碼的簡化更大!
另外,在并行流的循環(huán)下速度提升了一倍之多,當(dāng)單個循環(huán)耗時較多時,會拉大與前幾者的循環(huán)效率 ?(以上測試僅對于循環(huán)而言,其他類型業(yè)務(wù)處理,比如排序、求和、最大值等未做測試,個人猜測與以上測試結(jié)果相似)
六. Stream(流)注意項
并行Stream不是線程安全的,當(dāng)對循壞外部統(tǒng)一對象進行讀寫時候會造成意想不到的錯誤,這需要留意 因Stream總是惰性的,原對象是不可以被修改的,在集合處理完成后需要將處理結(jié)果放入一個新的集合容器內(nèi) 普通循環(huán)與Stream(非并行)循環(huán),在處理處理數(shù)據(jù)量比較大的時候效率是一致的,推薦使用Stream的形式 對于List刪除操作,目前只提供了removeIf方法來實現(xiàn),并不能使用并行方式 對于lambda表達式的寫法
當(dāng)表達式內(nèi)只有一個返回boolean類型的語句時候語句是可以簡寫的,例如:
persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
當(dāng)表達式內(nèi)會有一些復(fù)雜處理邏輯時需要加上大括號,這與初始化List參數(shù)方式大致一致
try?{
????????Thread.sleep(1);
????????p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
????}catch?(Exception?e){
????????e.printStackTrace();
????}
});
七. stream&Lambda表達式常用api方法
filter(過濾) map(映射轉(zhuǎn)換) mapTo[Int|Long|Double] (到基本類型流的轉(zhuǎn)換) flatMap(流展開合并) flatMapTo[Int|Long|Double] sorted(排序) distinct(不重復(fù)值) peek(執(zhí)行某種操作,流不變,可用于調(diào)試) limit(限制到指定元素數(shù)量) skip(跳過若干元素) toArray(轉(zhuǎn)為數(shù)組) reduce(推導(dǎo)結(jié)果) collect(聚合結(jié)果) min(最小值) max(最大值) count (元素個數(shù)) anyMatch (任一匹配) allMatch(所有都匹配) noneMatch(一個都不匹配) findFirst(選擇首元素) findAny(任選一元素)
好了,本篇到這里了,如果你想閱讀更多 Java 8 +?系列教程,可以關(guān)注公眾號Java技術(shù)棧回復(fù) java 獲取,我都寫了一大堆了。






關(guān)注Java技術(shù)棧看更多干貨

評論
圖片
表情

