实现原理
针对List去重,除了遍历去重,建议利用Set集合不允许重复元素的特点,通过List和Set互转实现去重
```java
public static List ridRepeat1(List list){
List newList = new ArrayList<>();
list.forEach(str -> {
if (!newList.contains(str)) {
newList.add(str);
}
});
return newList;
}
```
```java
public static List ridRepeat2(List list){
List newList = new ArrayList<>();
Set newSet = new HashSet<>();
list.forEach(str -> {
if (newSet.add(str)) {
newList.add(str);
}
});
return newList;
}
```
```java
public static List ridRepeat3(List list){
//List newList = new ArrayList<>(new HashSet<>(list));
Set newSet = new HashSet<>();
List newList = new ArrayList<>();
newSet.addAll(list);
newList.addAll(newSet);
return newList;
}
```
```java
public static List ridRepeat4(List list){
List newList = new ArrayList<>(new TreeSet<>(list));
return newList;
}
```
```java
public static List ridRepeat5(List list){
List newList = new ArrayList(new LinkedHashSet(list));
return newList;
}
```
```java
List strList = Arrays.asList("asdf", "sf", "pf", "c", "sg", "pg", "asdf", "pg");
List newList = strList.stream().distinct().collect(Collectors.toList());
System.out.println(newList);
```
备注
distinct()方法默认是按照父类Object的equals与hashCode工作的。所以:
上面的方法在List元素为基本数据类型及String类型时是可以的,但是如果List集合元素为对象,不会奏效。
不过如果你的实体类对象使用了目前广泛使用的lombok插件相关注解如:@Data,那么就会自动帮你重写了equals与hashcode方法,当然如果你的需求是根据某几个核心字段属性判断去重,那么你就要在该类中自定义重写equals与hashcode方法了。
自定义实体类
package com.neighbor.nbsp.entity;
import java.util.Objects;
/**
* @ClassName User
* @Description TODO 用户实体类$
* @Author charlesYan
* @Date 2020/2/18 11:49
* @Version 1.0
**/
public class User {
private int id;
private int age;
private String name;
public User() {
}
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
地址相等
if (this == o) return true;
//非空性:对于任意非空引用x,x.equals(null)应该返回false
if (o == null || getClass() != o.getClass()) return false;
if(o instanceof User){
User user = (User) o;
//需要比较的字段相等,则这两个对象相等
return age == user.age &&
Objects.equals(name, user.name);
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
}
测试main方法
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User(1, 90, "ellin"));
userList.add(new User(2, 98, "charles"));
userList.add(new User(3, 78, "frank"));
userList.add(new User(4, 78, "frank"));
userList.add(new User(5, 90, "ellin"));
//使用HashSet-无序
Set<User> userSet = new HashSet<>();
userSet.addAll(userList);
System.out.println(userSet);
//使用LinkedHashSet-有序
List<User> newUserList = new ArrayList<>(new LinkedHashSet<>(userList));
System.out.println(newUserList.toString());
}
特性介绍
该方式不能保持原列表顺序而是使用了TreeSet按照字典顺序排序后的列表,如果需求不需要按原顺序则可直接使用;
要想按原顺序,可以根据上面简写方式**再次加工处理使用stream流的sorted()**相关API写法
测试main方法
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;
import static java.util.Comparator.comparing;
public static void main(String[] args) {
//根据name属性去重
List<User> lt = userList.stream().collect(
collectingAndThen(
toCollection(() -> new TreeSet<>(Comparator.comparing(User::getName))), ArrayList::new)
);
System.out.println(lt);
//根据name,age属性去重,无序
List<User> lt2 = userList.stream().collect(
collectingAndThen(
toCollection(() -> new TreeSet<>(
comparing(o -> o.getName() + ";" + o.getAge())
)), ArrayList::new
)
);
System.out.println(lt2);
//根据name,age属性去重,保持原顺序
//该方法执行报错,欢迎大佬指点
List<User> lt3 = userList.stream().collect(
collectingAndThen(
toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getName() + "," + o.getAge()))),
v -> v.stream().sorted().collect(Collectors.toList())
)
);
}
实现方式
创建一个方法作为 Stream.filter() 的参数,其返回类型为 Predicate,原理就是判断一个元素能否加入到 Set 中去
案例代码
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User(1, 90, "ellin"));
userList.add(new User(2, 98, "charles"));
userList.add(new User(3, 78, "frank"));
userList.add(new User(4, 78, "frank"));
userList.add(new User(5, 90, "jack"));
userList.add(new User(6, 89, "jack"));
ObjectMapper objectMapper = new ObjectMapper();
System.out.println("去重前:" + objectMapper.writeValueAsString(userList));
List<User> newUserList1 = userList.stream().distinct().collect(Collectors.toList());
System.out.println("distinct去重:" + objectMapper.writeValueAsString(newUserList1));
//将distinctByKey()方法作为filter()的参数,过滤不能加入到set中的元素
List<User> newUserList2 = userList.stream().filter(
distinctByKey(o -> o.getName() + "," + o.getAge())
).collect(Collectors.toList());
System.out.println("自定义方法去重:" + objectMapper.writeValueAsString(newUserList2));
}
//自定义过滤方法
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
案例代码
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
userList.add(new User(1, 90, "ellin"));
userList.add(new User(2, 98, "charles"));
userList.add(new User(3, 78, "frank"));
userList.add(new User(4, 78, "frank"));
userList.add(new User(5, 90, "jack"));
userList.add(new User(6, 89, "jack"));
userList.stream()
.filter(p -> p.getAge() >= 80)//获取所有80岁以上的用户
// .sorted(Comparator.comparing(User::getAge))//依年纪升序排序
.sorted(Comparator.comparing(User::getAge).reversed())//依年纪降序排序
.collect(Collectors.toList())
.forEach(System.out::println);
boolean isAllAdult = userList.stream().
allMatch(p -> p.getAge() > 18);
System.out.println("是否所有的用户都大于18岁" + isAllAdult);
}
注意事项
**当equals方法被重写时,通常有必要重写 hashCode 方法,**以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码
抽取内容
根据《Effective Java》第二版的第九条:覆盖equals时总要覆盖hashCode 中的内容,总结如下:
在程序执行期间,只要equals方法的比较操作用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法必须始终如一地返回同一个整数。
如果两个对象根据equals方法比较是相等的,那么调用两个对象的hashCode方法必须返回相同的整数结果。
如果两个对象根据equals方法比较是不等的,则hashCode方法不一定得返回不同的整数。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
抽取内容
设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。如果在将一个对象用put()添加进HashMap时产生一个hashCdoe值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码。
https://www.cnblogs.com/zjfjava/p/9897650.html