Java8——Stream流式操作的一點小總結


我發現,自從我學了Stream流式操作之后,工作中使用到的頻率還是挺高的,因為stream配合着lambda表達式或者雙冒號(::)使用真的是優雅到了極致!今天就簡單分(搬)享(運)一下我對stream流式操作的一點理解

 

一、什么是流式操作?或者准確的說什么是“流”

所謂藝術來源於生活,所以不妨從一個生活中小例子展開說明一下。

通過組詞,流可以組成流動,流水,流經,流進流出.... 這些描述的都是一種狀態,是一種“運動”中的狀態,更加通俗的講,流水線。以往的流水線會有很多工人在,每一個工人負責一個環節,環環相聯下來之后最終會形成成品。好了,現在分解一下

  1. 首先需要有一條流水線(好給你流水線)

  2. 流水線有了,那么總得需要有人在作業吧,那就放幾個卡通人上去充當一下,他們將完成對原材料的篩選、清洗、組裝、貼標簽等操作,注意這是有順序,這也很好理解,下一道工序必須是在上一道工序的基礎上進行的,總不能跳過組裝就直接裝箱吧,雖然是可以,但是你發個空包給別人,真的好嗎?

    所以流水線+作業人員有了

  3. 經過一番操作之后,產出產品,之后就需要打包出廠,走進尋常百姓家了。最終完整的流程就是醬紫的

 

所以,對於“流式操作”可以想象成把一項需要完成的操作“打扁”成原材料,原材料會經過經過很多道工序,而經過多道工序時的狀態就是“流”,最終會對流進行一個打包收集,形成業務產品。

 

二、對於stream,你不得不了解的幾個概念

第一部分通過一個簡單的例子,闡述了一下先決概念,接下來就就對stream本身進行了解。

中間操作符與終止操作符

一句話講明,中間操作符可以有多個,每個中間操作符都是在前一個中間操作符的基礎上進行操作的,這就像極了剛剛講解的多道工序,二終止操作符有且僅有一個,也即處理完所有的中間操作之后,對最終產品進行收集或者消費的,流在這里之后就會得到一個實際的“產品”。

常見的中間操作符

操作符 對應的概念
flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作 比如把 int[]{2,3,4} 拍平 變成 2,3,4 也就是從原來的一個數據變成了3個數據,這里默認提供了拍平成int,long,double的操作符
limit 限流操作 比如數據流中有10個 我只要出前3個就可以使用
distint 去重操作 對重復元素去重,底層使用了equals方法
filter 過濾操作 把不想要的數據過濾
peek 挑出操作 如果想對數據進行某些操作,如:讀取、編輯修改等
skip 跳過操作 跳過某些元素
sorted(unordered) 排序操作 對元素排序,前提是實現Comparable接口,當然也可以自定義比較器

 

常見的終止操作符

操作符 對應的概念
collect 收集 使用系統提供的收集器可以將最終的數據流收集到List,Set,Map等容器中
count 統計操作 統計最終的數據個數
findFirst、findAny 查找操作 查找第一個、查找任何一個 返回的類型為Optional
noneMatch、allMatch、anyMatch 匹配操作 數據流中是否存在符合條件的元素 返回值為bool 值
min、max 最值操作,需要自定義比較器 返回數據流中最大最小的值
reduce 規約操作 將整個數據流的值規約為一個值,count、min、max底層就是使用reduce
forEach、forEachOrdered 遍歷操作 這里就是對最終的數據進行消費了
toArray 數組操作 將數據流的元素轉換成數組

 

⚠️所有的這些操作都是建立在流的基礎上,所以首先需要把對象打成流,而stream主要用於對象類型的集合,當然基礎類型的stream其實也是有提供的,這是打成流的方式不一致,待會會展示到底哪里不一致了。

三、stream的簡單小操作展示

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
class Person{
private Integer id;
private String name;
private Integer age;
private String sex;
}
/**
* @author Amg
* @Description 首先展現一下對於對象的集合跟基本類型是怎么打成流的
* @param
* @date 2020/9/13
* @return void
*/
public void tt(){

   //基於對象的集合
   List<Person> list = new ArrayList<>();
   Stream<Person> collection = list.stream();

   //基於基本類型的
   int[] array = new int[]{1,2,3,4,5,6,7,8,9};
   IntStream primitive = Arrays.stream(array);

   //挖一下源碼就會發現,其實Stream<T>跟IntStream都是繼承自BaseStream的,有Int自然也會有Double、Long等等
}

/**
* @author Amg
* @Description 第二個講一下遍歷過濾輸出一個給定的范圍的偶數
* @param
* @date 2020/9/13
* @return void
*/
public void testStream01() {
   IntStream.range(0, 20).filter(i -> (i % 2 == 0)).forEach(result -> System.out.print(result + " "));
}

//output 0 2 4 6 8 10 12 14 16 18 這里得注意了,對於lambda表達式跟方法引用的使用大家是要會的
/**
* @author Amg
* @Description 模擬場景就是一個帶重復數據的數組集合,把它轉換成一個去重后的List集合並且打印List中所有元素
* @param
* @date 2020/9/13
* @return void
*/
public void testStream02(){

   Object[] array = new Object[]{1,1,1,1,1,1,2,2,2,
                                 2,2,2,3,3,3,3,3,
                                 'a','a','a','a',
                                 "e","e","e","e",
                                 3.579f,3.579f,594d,594d,
                                 97586L,97586L
                                };
   Arrays.stream(array).distinct().collect(Collectors.toList()).forEach(res-> System.out.print(res + " "));

   //output 1 2 3 a e 3.579 594.0 97586 distinct就是去重的操作
}
/**
* @author Amg
* @Description 這次模擬的場景是對對象進行操作,把list轉換成map,map的鍵是對象的id主鍵,值是整個對象
* @param
* @date 2020/9/13
* @return void
*/
public void testStream03(){

   //prepareData()准備一些數據
   List<Person> list = prepareData();
   System.out.println(list);
   //Function.identify() 等價於 t -> t 返回自身
   //toMap的第三個參數可以解決沖突問題,當鍵值都是一致的情況,如果不添加第三個參數就會拋異常,下面的寫法代表,如果有沖突則保留其中一個
   Map<Integer, Person> result = list.stream().collect(Collectors.toMap(Person -> Person.getId() ,Function.identity(),(entity1,entity2)-> entity1));
   result.forEach((key,value)->{
       System.out.println(key + ":[" + value + "]");
  });
}

//output
/**  
[Person(id=1, name=z3, age=3, sex=男), Person(id=2, name=l4, age=4, sex=男), Person(id=3, name=w5, age=2, sex=男), Person(id=4, name=z6, age=13, sex=女), Person(id=5, name=t7, age=35, sex=女), Person(id=5, name=t7, age=35, sex=女)]
1:[Person(id=1, name=z3, age=3, sex=男)]
2:[Person(id=2, name=l4, age=4, sex=男)]
3:[Person(id=3, name=w5, age=2, sex=男)]
4:[Person(id=4, name=z6, age=13, sex=女)]
5:[Person(id=5, name=t7, age=35, sex=女)]

*/
/**
* @author Amg
* @Description 再考慮一個業務,從數據庫中獲取到對應表中指定的數據集,然后我們需要的是該表的主鍵id值,
* 然后通過這個主鍵id值去查,另外一張表的數據,得到的數據才是我們真實需要的
* @param
* @date 2020/9/13
* @return void
*/
public void testStream04(){

   //模擬環境,數據直接從方法里面模擬
   List<Person> list = getAllPersonById();

   //原操作是如此的
   List<Integer> personId = new ArrayList<>();
   for (Person person : list) {
       personId.add(person.getId());
  }

   //list里面存放的是所有的Person對象,我們將通過Stream流操作抽取出我們需要id,一行代碼可以完成
   List<Integer> result = list.stream().map(Person::getId).collect(Collectors.toList());
   System.out.println(result);
   
   //output [1, 2, 3, 4, 5, 5]
}

好了,這就是今天分享的小內容,感謝你的觀看,祝你生活愉快!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM