使用 Java 8 Stream 優雅的找出重複數據

2022-01-30 AmberBala

最近經常遇到問題:要獲取到集合中某一屬性值重複的數據,除了for 循環,還有更簡單的處理方式?

先來引入 Stream 流的概念。

Stream 闡述

Stream API(java.util.stream.*) 是 Java 8 中新增重要特性。
Stream 將要處理的元素集合看作一種流,由於java.util.stream.Stream 是一個 Interface ,在其中提供了函數方法,
使流在管道中進行一系列處理(如過濾,映射,聚合等)後生成的結果集合,類似於在資料庫執行 SQL 語句。
這個過程通常不會對數據源造成影響。

List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");       myList.stream()         .filter(s -> s.startsWith("c"))         .map(String::toUpperCase)         .sorted()         .forEach(System.out::println);    

在以上示例中, 創建 Stream 流,filter,map 和 sorted 是中間操作,而 forEach 是一個終端操作。Stream操作鏈稱為操作管道。

Stream 用法

可以從各種數據源中創建 Stream 流,其中以 Collection 集合最為常見。
如 List 和 Set 均支持 stream() 方法來創建順序流 stream() 或者是並行流 parallelStream()。

一、常用創建 Stream 流方法

1.使用 Collection 下的 stream() 和 parallelStream() 方法來創建 Stream

List<String> list = new ArrayList<>();Stream<String> stream = list.stream(); Stream<String> parallelStream = list.parallelStream(); 

2.Arrays 提供了創建流的靜態方法 stream(),將數組轉成流

Integer[] nums = new Integer[10];Stream<Integer> stream = Arrays.stream(nums);

3.使用 Stream 中的靜態方法:of()、iterate()、generate()

 Stream<Integer> stream = Stream.of(1,2,3,4,5,6);     Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6); stream2.forEach(System.out::println);  Stream<Double> stream3 = Stream.generate(Math::random).limit(2); stream3.forEach(System.out::println);

4.使用 Pattern.splitAsStream() 方法,將字符串分隔成流

Pattern pattern = Pattern.compile(",");Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");stringStream.forEach(System.out::println);

5.一些類也提供了創建流的方法:

IntStream.range(start, stop);BufferedReader.lines();Random.ints();

二、中間操作 Stream 流

1.filter:用於通過設置的條件過濾出元素,其中 java.util.Objects 提供了空元素的過濾

2.映射 map 方法用於映射每個元素到對應的結果

3.排序 sorted:使用 java.util.Comparator 或者 reversed 更方便的對流進行升降排序

4.distinct:通過流中元素的 hashCode() 和 equals() 去除重複元素

5.skip(n):跳過n元素,配合limit(n)可實現分頁

6.limit(n):用於獲取指定數量的流…

三、終端操作 Stream 流

1.forEach() 迭代流中的每個元素,java.util.function.Consumer 接受參數沒有返回值

Stream.of(1,2,3,4,5).forEach(System.out::println);

2.collect() 可用於返回列表或字符串,java.util.Collectors 類中有求和、計算均值、取最值、字符串連接等多種收集方法。

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");List<String> count = strings.stream().filter(string -> string.isEmpty()).collect(Collectors.toList());System.out.println(count.size()); 

3.reduce 用於對stream中元素進行聚合求值,操作函數 accumulator 接受兩個參數x,y返回r

4.anyMatch()、allMatch()、noneMatch() 接收參數Predicate,返回boolean。

5.findFirst()、findAny()、count()、max()、min() …

使用 Stream 流解決集合中數據重複問題

我們以 Employee 為實體,對比 獲取重複code值的 寫法:

Employee 實體:

public class Employee extends Model<Employee> {  @ApiModelProperty(value = "ID")  @TableField("ID")  private Long id;
@ApiModelProperty(value = "編碼") @TableId("CODE") private String code;
@ApiModelProperty(value = "姓名") @TableField("NAME") private String name;
@ApiModelProperty(value = "年齡") @TableField("AGE") private Integer age; ... }

for 寫法:

List<String> duplicate_code = new ArrayList<>();List<Employee> employeeList = fromDB();if (employeeList.size() > 0) {  for (int i = 0; i < employeeList.size(); i++) {      Employee employee = employeeList.get(i);      for (Employee entity : employeeList) {          String code = entity.getCode();          if (StringUtils.isBlank(code) && StringUtils.isBlank(employee.getCode()) && code.equals(employee.getCode())) {              duplicate_code.add(code);          }      }  }}

Stream 寫法:

List<String> duplicate_code = new ArrayList<>();List<Employee> employeeList = fromDB();Map<Object, Long> map = employeeList.stream().collect(Collectors.groupingBy(employee -> employee.getCode(), Collectors.counting()));Stream<Object> stringStream = map.entrySet().stream().filter(entry -> entry.getValue() > 1).map(entry -> entry.getKey());stringStream.forEach(str -> {  duplicate_code.add(String.valueOf(str));});

由此可見,使用Java 8 的 Stream 流方式獲取到集合中某一屬性值重複數據的問題更方便、簡潔!

了解更多有關 Java8 Stream 流的相關信息,請參考 Stream Javadoc 閱讀官方文檔。

相關焦點

  • Java 8 Stream 教程 (一)
    posts/2014/07/31/java8-stream-tutorial-examples/(點擊閱讀原文前往)這一示例驅動的教程對Java 8stream進行了深入的闡述。但是Java 8 Stream是完全不同的東西。Stream是Monads,因此在將函數編程引入Java方面起了很大作用:在函數式編程中,monad是一個表示計算(步驟序列)的結構。一個帶有monad結構的類型或該類型的嵌套函數定義了其鏈式操作的意義。本指南教你如何使用Java 8 Stream,以及如何使用不同種類的可用的stream操作。
  • Java Stream
    流水線的操作可以 看作對數據源進行資料庫式查詢。2. 內部迭代與使用迭代器顯式迭代的集合不同,流的迭代操作是在背後進行的。看一段能夠顯示這些概念的代碼,需求是: 把集合中年齡小於等於20的人的名字取出來並排序public List<String> java8(List<User> users){        List<String> userNames = users.stream()                .filter(user
  • Java 8 中處理集合的優雅姿勢——Stream
    相比之下,關係型資料庫中也同樣有這些操作,但是在Java 8之前,集合和數組的處理並不是很便捷。不過,這一問題在Java 8中得到了改善,Java 8 API添加了一個新的抽象稱為流Stream,可以讓你以一種聲明的方式處理數據。本文就來介紹下如何使用Stream。
  • Java 8中處理集合的優雅姿勢——Stream
    相比之下,關係型資料庫中也同樣有這些操作,但是在Java 8之前,集合和數組的處理並不是很便捷。不過,這一問題在Java 8中得到了改善,Java 8 API添加了一個新的抽象稱為流Stream,可以讓你以一種聲明的方式處理數據。本文就來介紹下如何使用Stream。特別說明一下,關於Stream的性能及原理不是本文的重點,如果大家感興趣後面會出文章單獨介紹。
  • Java學習進階-Stream流
    Stream流不能重複操作.3. Stream流中不能存儲數據.4. Stream流的操作不會影響數據源數據.  Collection的stream()方法- 使用Stream流的of()方法package com.p04Stream常用方法;import java.util.stream.Stream;public class Test_forEach { public static void main(String[] args) {
  • 簡潔方便的集合處理——Java 8 stream流
    而且java8的很多新特性都是革命性的,比如各種集合的優化、lambda表達式等,所以我們還是要去了解java8的魅力。今天我們來學習java8的Stream,並不需要理論基礎,直接可以上手去用。我接觸stream的原因,是我要搞一個用戶收入消費的數據分析。起初的統計篩選分組都是打算用sql語言直接從mysql裡得到結果來展現的。
  • Java Stream Pipeline 流水線:Stream 基礎
    乾貨分享來源:傷神https://www.shangyang.me/2019/03/29/java-pipeline-01-stream-tutorial/概述本文將重點提煉 State of the Lambda - Libraries Edition: http://cr.openjdk.java.net/~briangoetz
  • java8 stream的這些開發技巧,你值得好好收藏
    stream的工作流程圖為什麼要學stream的鏈式編程方式業務需求1:指定一個字符串數組,找出裡面相同的元素,並且統計重複的次數。但是,用java8 stream的語法,又只用一行代碼就完成功能了,真棒。
  • Java 8的Stream代碼,你能看懂嗎?
    以下為正文:在Java中,集合和數組是我們經常會用到的數據結構,需要經常對他們做增、刪、改、查、聚合、統計、過濾等操作。相比之下,關係型資料庫中也同樣有這些操作,但是在Java 8之前,集合和數組的處理並不是很便捷。不過,這一問題在Java 8中得到了改善,Java 8 API添加了一個新的抽象稱為流Stream,可以讓你以一種聲明的方式處理數據。
  • 每日一課 | Java 8 Stream List 獲取最後一個元素
    在Java 8中,我們可以使用reduce或skip獲取Stream
  • 20 個實例玩轉 Java 8 Stream
    終端操作,每個流只能進行一次終端操作,終端操作結束後流無法再次使用。終端操作會產生一個新的集合或值。1. stream不存儲數據,而是按照特定的規則對數據進行計算,一般會輸出結果。2. stream不會改變數據源,通常情況下會產生一個新的集合或一個值。3. stream具有延遲執行特性,只有調用終端操作時,中間操作才會執行。
  • Java8 的 Stream 快速實現List轉map 、分組、過濾等騷操作!
    今天,磊哥,跟大家分享一下,Java8快速實現List轉map 、分組、過濾等操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧利用java8新特性,可以用簡潔高效的代碼來實現一些數據處理。
  • Java8 中用法優雅的 Stream,性能也「優雅」嗎?
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫ava8的Stream API可以極大提高Java程式設計師的生產力,讓程式設計師寫出高效率、乾淨、簡潔的代碼。那麼,Stream API的性能到底如何呢,代碼整潔的背後是否意味著性能的損耗呢?
  • 每日一課 | 示例 Java 8 Stream 的 iterate 處理
    在Java 8中,我們可以使用Stream.iterate創建流值,
  • Java簡潔之道:如何優雅地玩轉List
    對於List存儲數據的處理,如排序、篩選等操作,我們通常使用Iterator或者Foreach的方式對集合進行遍歷,並通過if.else.判斷完成數據的處理,代碼如下所示,這樣的代碼看起來十分冗長,不易於維護。對於一個崇尚代碼簡潔的程式設計師來說,這是不能容忍的!
  • 20 個實例玩轉 Java 8 Stream,寫的太好了!
    將員工按薪資從高到低排序,同樣薪資者年齡小者在前。將員工按性別分類,將員工按性別和地區分類,將員工按薪資是否高於8000分為兩部分。用傳統的迭代處理也不是很難,但代碼就顯得冗餘了,跟Stream相比高下立判。
  • Java8 中用法優雅的 Stream,性能也""優雅""嗎?
    使用Stream或許很容易寫入如下形式的代碼:int longestStringLengthStartingWithA        = strings.stream>> 操作如何記錄注意這裡使用的是「操作(operation)」一詞,指的是「Stream中間操作」的操作,很多Stream操作會需要一個回調函數(Lambda表達式),因此一個完整的操作是<數據來源,操作,回調函數>構成的三元組。
  • 使用Java8 Stream API對Map類型按照鍵或值進行排序
    在這篇文章中,您將學習如何使用Java對Map按照鍵或值進行排序。前幾日有位朋友面試遇到了這個問題,看似很簡單的問題,但是如果不仔細研究一下也是很容易讓人懵圈的面試題。所以我決定寫這樣一篇文章。在Java中,有多種方法可以對Map進行排序,但是我們將重點介紹Java 8 Stream,這是實現目標的一種非常優雅的方法。
  • Java8 stream 處理 List 交集、差集、去重等
    ("1","趙鐵柱")); // 找兩個班名字相同的同學(取交集),比較用的是重寫的equals() List<Student> sameName=class01.stream().filter(class02::contains).collect(Collectors.toList()); sameName.stream().forEach(student
  • 基礎篇:JAVA.Stream函數,優雅的數據流操作
    前言平時操作集合數據,我們一般都是for或者iterator去遍歷,不是很好看。java提供了Stream的概念,它可以讓我們把集合數據當做一個個元素在處理,並且提供多線程模式並發流和CompletableFuture的配合使用「關注公眾號,一起交流,微信搜一搜: 潛行前行」1 stream的構造方式stream內置的構造方法public static<T> Stream