最近經常遇到問題:要獲取到集合中某一屬性值重複的數據,除了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 集合最為常見。
一、常用創建 Stream 流方法
如 List 和 Set 均支持 stream() 方法來創建順序流 stream() 或者是並行流 parallelStream()。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 閱讀官方文檔。