最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java 8 Stream.distinct() 列表去重的操作

 更新時間:2020年12月08日 11:23:36   作者:Haiyoung  
這篇文章主要介紹了Java 8 Stream.distinct() 列表去重的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

在這篇文章里,我們將提供Java8 Stream distinct()示例。 distinct()返回由該流的不同元素組成的流。distinct()是Stream接口的方法。

distinct()使用hashCode()和equals()方法來獲取不同的元素。因此,我們的類必須實現(xiàn)hashCode()和equals()方法。

如果distinct()正在處理有序流,那么對于重復元素,將保留以遭遇順序首先出現(xiàn)的元素,并且以這種方式選擇不同元素是穩(wěn)定的。

在無序流的情況下,不同元素的選擇不一定是穩(wěn)定的,是可以改變的。distinct()執(zhí)行有狀態(tài)的中間操作。

在有序流的并行流的情況下,保持distinct()的穩(wěn)定性是需要很高的代價的,因為它需要大量的緩沖開銷。如果我們不需要保持遭遇順序的一致性,那么我們應該可以使用通過BaseStream.unordered()方法實現(xiàn)的無序流。

1. Stream.distinct()

distinct()方法的聲明如下:

Stream<T> distinct()

它是Stream接口的方法。在此示例中,我們有一個包含重復元素的字符串數(shù)據(jù)類型列表

DistinctSimpleDemo.java

package com.concretepage;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class DistinctSimpleDemo {
 public static void main(String[] args) {
 List<String> list = Arrays.asList("AA", "BB", "CC", "BB", "CC", "AA", "AA");
 long l = list.stream().distinct().count();
 System.out.println("No. of distinct elements:"+l);
 String output = list.stream().distinct().collect(Collectors.joining(","));
 System.out.println(output);
 }
} 

Output

No. of distinct elements:3

AA,BB,CC

2. Stream.distinct() with List of Objects

在此示例中,我們有一個Book對象列表。 為了對列表進行去重,該類將重寫hashCode()和equals()。

Book.java

package com.concretepage;
public class Book {
 private String name;
 private int price;
 public Book(String name, int price) {
 this.name = name;
 this.price = price;
 }
 public String getName() {
 return name;
 }
 public int getPrice() {
 return price;
 }
 @Override
 public boolean equals(final Object obj) {
 if (obj == null) {
 return false;
 }
 final Book book = (Book) obj;
 if (this == book) {
 return true;
 } else {
 return (this.name.equals(book.name) && this.price == book.price);
 }
 }
 @Override
 public int hashCode() {
 int hashno = 7;
 hashno = 13 * hashno + (name == null ? 0 : name.hashCode());
 return hashno;
 }
} 

DistinctWithUserObjects.java

package com.concretepage;
import java.util.ArrayList;
import java.util.List;
public class DistinctWithUserObjects {
 public static void main(String[] args) {
 List<Book> list = new ArrayList<>();
 {
 list.add(new Book("Core Java", 200));
 list.add(new Book("Core Java", 200));
 list.add(new Book("Learning Freemarker", 150)); 
 list.add(new Book("Spring MVC", 300));
 list.add(new Book("Spring MVC", 300));
 }
 long l = list.stream().distinct().count();
 System.out.println("No. of distinct books:"+l);
 list.stream().distinct().forEach(b -> System.out.println(b.getName()+ "," + b.getPrice()));
 }
}

Output

No. of distinct books:3
Core Java,200
Learning Freemarker,150
Spring MVC,300 

3. Distinct by Property

distinct()不提供按照屬性對對象列表進行去重的直接實現(xiàn)。它是基于hashCode()和equals()工作的。

如果我們想要按照對象的屬性,對對象列表進行去重,我們可以通過其它方法來實現(xiàn)。

如下代碼段所示:

static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
 Map<Object,Boolean> seen = new ConcurrentHashMap<>();
 return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
} 

上面的方法可以被Stream接口的 filter()接收為參數(shù),如下所示:

list.stream().filter(distinctByKey(b -> b.getName()));

distinctByKey()方法返回一個使用ConcurrentHashMap 來維護先前所見狀態(tài)的 Predicate 實例,如下是一個完整的使用對象屬性來進行去重的示例。

DistinctByProperty.java

package com.concretepage;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
public class DistinctByProperty {
 public static void main(String[] args) {
 List<Book> list = new ArrayList<>();
 {
 list.add(new Book("Core Java", 200));
 list.add(new Book("Core Java", 300));
 list.add(new Book("Learning Freemarker", 150));
 list.add(new Book("Spring MVC", 200));
 list.add(new Book("Hibernate", 300));
 }
 list.stream().filter(distinctByKey(b -> b.getName()))
 .forEach(b -> System.out.println(b.getName()+ "," + b.getPrice())); 
 }
 private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
 Map<Object,Boolean> seen = new ConcurrentHashMap<>();
 return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
 }
} 

Output

Core Java,200
Learning Freemarker,150
Spring MVC,200
Hibernate,300 

from : https://www.concretepage.com/java/jdk-8/java-8-distinct-example

補充知識:List集合常規(guī)去重與java8新特性去重方法

一、常規(guī)去重

碰到List去重的問題,除了遍歷去重,我們常常想到利用Set集合不允許重復元素的特點,通過List和Set互轉,來去掉重復元素。

// 遍歷后判斷賦給另一個list集合,保持原來順序
 public static void ridRepeat1(List<String> list) {
  System.out.println("list = [" + list + "]");
  List<String> listNew = new ArrayList<String>();
  for (String str : list) {
   if (!listNew.contains(str)) {
    listNew.add(str);
   }
  }
  System.out.println("listNew = [" + listNew + "]");
 }
 // set集合去重,保持原來順序
 public static void ridRepeat2(List<String> list) {
  System.out.println("list = [" + list + "]");
  List<String> listNew = new ArrayList<String>();
  Set set = new HashSet();
  for (String str : list) {
   if (set.add(str)) {
    listNew.add(str);
   }
  }
  System.out.println("listNew = [" + listNew + "]");
 }
 // Set去重  由于Set的無序性,不會保持原來順序
 public static void ridRepeat3(List<String> list) {
  System.out.println("list = [" + list + "]");
  Set set = new HashSet();
  List<String> listNew = new ArrayList<String>();
  set.addAll(list);
  listNew.addAll(set);
  System.out.println("listNew = [" + listNew + "]");
 }
 // Set去重(將ridRepeat3方法縮減為一行) 無序
 public static void ridRepeat4(List<String> list) {
  System.out.println("list = [" + list + "]");
  List<String> listNew = new ArrayList<String>(new HashSet(list));
  System.out.println("listNew = [" + listNew + "]");
 }
 // Set去重并保持原先順序
 public static void ridRepeat5(List<String> list) {
  System.out.println("list = [" + list + "]");
  List<String> listNew2= new ArrayList<String>(new LinkedHashSet<String>(list));
  System.out.println("listNew = [" + listNew + "]");
 }

二、java8的stream寫法實現(xiàn)去重

1、distinct去重

//利用java8的stream去重
 List uniqueList = list.stream().distinct().collect(Collectors.toList());
 System.out.println(uniqueList.toString());

distinct()方法默認是按照父類Object的equals與hashCode工作的。所以:

上面的方法在List元素為基本數(shù)據(jù)類型及String類型時是可以的,但是如果List集合元素為對象,卻不會奏效。不過如果你的實體類對象使用了目前廣泛使用的lombok插件相關注解如:@Data,那么就會自動幫你重寫了equals與hashcode方法,當然如果你的需求是根據(jù)某幾個核心字段屬性判斷去重,那么你就要在該類中自定義重寫equals與hashcode方法了。

2、也可以通過新特性簡寫方式實現(xiàn)

不過該方式不能保持原列表順序而是使用了TreeSet按照字典順序排序后的列表,如果需求不需要按原順序則可直接使用。

//根據(jù)name屬性去重
List<User> lt = list.stream().collect(
  collectingAndThen(
    toCollection(() -> new TreeSet<>(Comparator.comparing(User::getName))), ArrayList::new));
System.out.println("去重后的:" + lt);
//根據(jù)name與address屬性去重
List<User> lt1 = list.stream().collect(
  collectingAndThen(
    toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getName() + ";" + o.getAddress()))), ArrayList::new));
System.out.println("去重后的:" + lt);

當需求中明確有排序要求也可以按上面簡寫方式再次加工處理使用stream流的sorted()相關API寫法。

List<User> lt = list.stream().collect(
    collectingAndThen(
      toCollection(() -> new TreeSet<>(Comparator.comparing(User::getName))),v -> v.stream().sorted().collect(Collectors.toList())));

3、通過 filter() 方法

我們首先創(chuàng)建一個方法作為 Stream.filter() 的參數(shù),其返回類型為 Predicate,原理就是判斷一個元素能否加入到 Set 中去,代碼如下:

private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
 Set<Object> seen = ConcurrentHashMap.newKeySet();
 return t -> seen.add(keyExtractor.apply(t));
}

使用如下:

@Test
 public void distinctByProperty() throws JsonProcessingException {
 // 這里第二種方法我們通過過濾來實現(xiàn)根據(jù)對象某個屬性去重
 ObjectMapper objectMapper = new ObjectMapper();
 List<Student> studentList = getStudentList();
 
 System.out.print("去重前  :");
 System.out.println(objectMapper.writeValueAsString(studentList));
 studentList = studentList.stream().distinct().collect(Collectors.toList());
 System.out.print("distinct去重后:");
 System.out.println(objectMapper.writeValueAsString(studentList));
 // 這里我們將 distinctByKey() 方法作為 filter() 的參數(shù),過濾掉那些不能加入到 set 的元素
 studentList = studentList.stream().filter(distinctByKey(Student::getName)).collect(Collectors.toList());
 System.out.print("根據(jù)名字去重后 :");
 System.out.println(objectMapper.writeValueAsString(studentList));
 }

去重前:

[{"stuNo":"001","name":"Tom"},{"stuNo":"001","name":"Tom"},{"stuNo":"003","name":"Tom"}]

distinct去重后:

[{"stuNo":"001","name":"Tom"},{"stuNo":"003","name":"Tom"}]

根據(jù)名字去重后 :

[{"stuNo":"001","name":"Tom"}]

三、相同元素累計求和等操作

除了集合去重意外,工作中還有一種常見的需求,例如:在所有商品訂單中,計算同一家店鋪不同商品名稱的商品成交額,可以直接通過sql語句獲取,這里寫一下如何通過java簡單實現(xiàn)。舉一個類似的案例:計算相同姓名與住址的用戶年齡之和。

User.java

package com.example.demo.dto;
import java.io.Serializable;
import java.util.Objects;
/**
 * @author: shf
 * description:
 * date: 2019/10/30 10:21
 */
public class User implements Serializable {
 private static final long serialVersionUID = 1L;
 private Long id;
 private String name;
 private String address;
 private Integer age;
 public User() {
 }
 public User(String name, String address, Integer age) {
  this.name = name;
  this.address = address;
  this.age = age;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getAddress() {
  return address;
 }
 public void setAddress(String address) {
  this.address = address;
 }
 public Integer getAge() {
  return age;
 }
 public void setAge(Integer age) {
  this.age = age;
 }
 @Override
 public String toString() {
  return "User{" +
    "name='" + name + '\'' +
    ", address='" + address + '\'' +
    ", age=" + age +
    '}';
 }
 @Override
 public boolean equals(Object obj) {
  if (this == obj) {
   return true;//地址相等
  }
  if (obj == null) {
   return false;//非空性:對于任意非空引用x,x.equals(null)應該返回false。
  }
  if (obj instanceof User) {
   User other = (User) obj;
   //需要比較的字段相等,則這兩個對象相等
   if (Objects.equals(this.name, other.name)
     && Objects.equals(this.address, other.address)) {
    return true;
   }
  }
  return false;
 }
 @Override
 public int hashCode() {
  return Objects
    .hash(name, address);
 }
}

測試代碼:

package com.example.demo;
import com.example.demo.dto.User;
import java.util.*;
import java.util.stream.Collectors;
public class FirCes {
 public static void main(String[] args) {
  /*構建測試數(shù)據(jù)集合*/
  User user1 = new User("a小張1", "a1", 10);
  User user2 = new User("b小張2", "a2", 10);
  User user3 = new User("c小張3", "a3", 10);
  User user3_3 = new User("c小張3", "a", 10);
  User user33 = new User("c小張3", "a3", 10);
  User user4 = new User("d小張4", "a4", 10);
  User user5 = new User("e小張5", "a5", 10);
  List<User> list = new ArrayList<>();
  list.add(user1);
  list.add(user2);
  list.add(user3);
  list.add(user3_3);
  list.add(user33);
  list.add(user4);
  list.add(user5);
  //按相同name與address屬性分組User用戶
  Map<User, List<User>> listMap = list.stream().collect(Collectors.groupingBy(v -> v));
  /*先看一下分組效果*/
  listMap.forEach((key, value) -> {
   System.out.println("========");
   System.out.println("key:" + key);
   value.forEach(obj -> {
    System.out.println(obj);
   });
  });
  /*最終執(zhí)行結果*/
  List<User> listNew = listMap.keySet().stream().map(u -> {
   int sum = listMap.get(u).stream().mapToInt(i -> i.getAge()).sum();
   //需要注意的是:這里也會改變原list集合中的原數(shù)據(jù)。因為這里的u分組時就是來自原集合中的一個地址對象,
   // 即:指向了原集合中的一個對象的地址。如果不想原集合被影響,這里可以new User()新的對象賦值并返回新對象
   u.setAge(sum);
   return u;
  }).collect(Collectors.toList());
  System.out.println("listNew:" + listNew);
  System.err.println("list:" + list);
  //但是一個實體類只能重寫一次equals方法,如果有多種判別需求就不好滿足了,
  // 可以定義多個不同類名相同屬性的類或者下面這種方式解決
  Map<String, List<User>> listMap1 = list.stream().collect(Collectors
    .groupingBy(v -> Optional.ofNullable(v.getName()).orElse("") + "_" + Optional.ofNullable(v.getAddress()).orElse("")));
  /*先看一下分組效果*/
  listMap1.forEach((key, value) -> {
   System.out.println("========");
   System.out.println("key:" + key);
   value.forEach(obj -> {
    System.out.println(obj);
   });
  });
  /*最終執(zhí)行結果*/
  List<User> listNew1 = listMap1.keySet().stream().map(u -> {
   int sum = listMap1.get(u).stream().mapToInt(i -> i.getAge()).sum();
   User user = listMap1.get(u).get(0);
   //這里和上面一樣的原理,也會影響原list集合中的被指向的地址的對象數(shù)據(jù)
   user.setAge(sum);
   return user;
  }).collect(Collectors.toList());
  System.out.println("listNew1:" + listNew1);
  System.err.println("list:" + list);
 }
 
}

打印日志:

========
key:User{name='b小張2', address='a2', age=10}
User{name='b小張2', address='a2', age=10}
========
key:User{name='c小張3', address='a', age=10}
User{name='c小張3', address='a', age=10}
========
key:User{name='c小張3', address='a3', age=10}
User{name='c小張3', address='a3', age=10}
User{name='c小張3', address='a3', age=10}
========
key:User{name='a小張1', address='a1', age=10}
User{name='a小張1', address='a1', age=10}
========
key:User{name='d小張4', address='a4', age=10}
User{name='d小張4', address='a4', age=10}
========
key:User{name='e小張5', address='a5', age=10}
User{name='e小張5', address='a5', age=10}
listNew:[User{name='b小張2', address='a2', age=10}, User{name='c小張3', address='a', age=10}, User{name='c小張3', address='a3', age=20}, User{name='a小張1', address='a1', age=10}, User{name='d小張4', address='a4', age=10}, User{name='e小張5', address='a5', age=10}]
list:[User{name='a小張1', address='a1', age=10}, User{name='b小張2', address='a2', age=10}, User{name='c小張3', address='a3', age=20}, User{name='c小張3', address='a', age=10}, User{name='c小張3', address='a3', age=10}, User{name='d小張4', address='a4', age=10}, User{name='e小張5', address='a5', age=10}]
========
key:a小張1_a1
User{name='a小張1', address='a1', age=10}
========
key:c小張3_a
User{name='c小張3', address='a', age=10}
========
key:d小張4_a4
User{name='d小張4', address='a4', age=10}
========
key:e小張5_a5
User{name='e小張5', address='a5', age=10}
========
key:b小張2_a2
User{name='b小張2', address='a2', age=10}
========
key:c小張3_a3
User{name='c小張3', address='a3', age=20}
User{name='c小張3', address='a3', age=10}
listNew1:[User{name='a小張1', address='a1', age=10}, User{name='c小張3', address='a', age=10}, User{name='d小張4', address='a4', age=10}, User{name='e小張5', address='a5', age=10}, User{name='b小張2', address='a2', age=10}, User{name='c小張3', address='a3', age=30}]
list:[User{name='a小張1', address='a1', age=10}, User{name='b小張2', address='a2', age=10}, User{name='c小張3', address='a3', age=30}, User{name='c小張3', address='a', age=10}, User{name='c小張3', address='a3', age=10}, User{name='d小張4', address='a4', age=10}, User{name='e小張5', address='a5', age=10}]
Process finished with exit code 0

以上這篇Java 8 Stream.distinct() 列表去重的操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • spring中aop的xml配置方法實例詳解

    spring中aop的xml配置方法實例詳解

    AOP的配置方式有2種方式:xml配置和AspectJ注解方式。下面這篇文章主要給大家介紹了關于spring中aop的xml配置方法的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-07-07
  • SpringSecurity?認證實現(xiàn)流程分析

    SpringSecurity?認證實現(xiàn)流程分析

    SpringSecurity框架通過一個過濾器鏈來處理認證和授權,主要包括UsernamePasswordAuthenticationFilter負責處理登錄請求,本文給大家介紹SpringSecurity?認證實現(xiàn)登錄校驗,感興趣的朋友跟隨小編一起看看吧
    2024-10-10
  • Java11新特性之HttpClient小試牛刀

    Java11新特性之HttpClient小試牛刀

    本文主要研究一下Java11的HttpClient的基本使用。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • 聊聊SpringCloud中的Ribbon進行服務調用的問題

    聊聊SpringCloud中的Ribbon進行服務調用的問題

    SpringCloud-Ribbon是基于Netflix?Ribbon實現(xiàn)的一套客戶端負載均衡的工具。本文給大家介紹SpringCloud中的Ribbon進行服務調用的問題,感興趣的朋友跟隨小編一起看看吧
    2022-01-01
  • SpringBoot模塊多項目解耦的最佳實踐

    SpringBoot模塊多項目解耦的最佳實踐

    為了提高代碼質量和靈活性,在Spring Boot項目中采用策略模式是一個有效的方法,該模式允許定義一系列算法并將每一個封裝起來,使它們可以互相替換,本文給大家介紹了SpringBoot模塊多項目解耦的最佳實踐,需要的朋友可以參考下
    2025-02-02
  • 詳解Java數(shù)組的定義和聲明方法

    詳解Java數(shù)組的定義和聲明方法

    在Java開發(fā)中,數(shù)組是最常用的數(shù)據(jù)結構之一,因此,深入了解Java數(shù)組的定義和聲明是非常必要的,本文將詳細介紹Java數(shù)組的定義和聲明方法,以及其在實際開發(fā)中的應用場景、優(yōu)缺點等方面,需要的朋友可以參考下
    2023-11-11
  • SpringBoot?AOP?@Pointcut切入點表達式排除某些類方式

    SpringBoot?AOP?@Pointcut切入點表達式排除某些類方式

    這篇文章主要介紹了SpringBoot?AOP?@Pointcut切入點表達式排除某些類方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 基于Java隨機生成手機短信驗證碼的實例代碼

    基于Java隨機生成手機短信驗證碼的實例代碼

    這篇文章主要介紹了Java隨機生成手機短信驗證碼的實例代碼,代碼分為哦簡單版和復雜版,需要的朋友可以參考下
    2019-04-04
  • spring @Profiles和@PropertySource實現(xiàn)根據(jù)環(huán)境切換配置文件

    spring @Profiles和@PropertySource實現(xiàn)根據(jù)環(huán)境切換配置文件

    這篇文章主要介紹了spring @Profiles和@PropertySource根據(jù)環(huán)境切換配置文件,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 解決JavaWeb讀取本地json文件以及亂碼的問題

    解決JavaWeb讀取本地json文件以及亂碼的問題

    今天小編就為大家分享一篇解決JavaWeb讀取本地json文件以及亂碼的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-06-06

最新評論

阿巴嘎旗| 平潭县| 依安县| 错那县| 湖口县| 徐汇区| 宁波市| 磐安县| 吴忠市| 义马市| 横峰县| 德化县| 平阴县| 青铜峡市| 开阳县| 芒康县| 阿坝县| 衡阳市| 枣庄市| 五莲县| 平定县| 周至县| 南部县| 颍上县| 阿尔山市| 开远市| 鱼台县| 卢湾区| 班玛县| 阿克| 上高县| 家居| 武宣县| 清流县| 东平县| 烟台市| 资讯 | 新巴尔虎左旗| 辉县市| 金华市| 麦盖提县|