新建一个list数组:
List list = new ArrayList();
list.add(26);
list.add(39);
list.add(39);
list.add(39);
list.add(39);
list.add(5);
list.add(40);
list.add(39);
list.add(25);
System.out.println(list);
注意:去重对象,他只能去重对象中所有字段都一样的,不能针对单个去重
List newList = list.stream().distinct().collect(Collectors.toList());
System.out.println(“java8新特性stream去重:”+newList);
list.add(39);
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list))
}
stream的distinct去重方法,是根据 Object.equals,和 Object.hashCode这两个方法来判断是否重复的。
所以我们可以利用这个特性 ,重写pojo的 Object.equals,和 Object.hashCode这两个方法,来实现。
1、重写Book类的equals和hashCode方法,以name来判断比较是否相同,然后用stream的distinct方法来去重
class Book {
...
@Override
public String toString() {
return String.format("(%s,%s,%s)", id, name, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(createTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book book = (Book) o;
return Objects.equals(name, book.name);
}
}
List<Book> distinctNameBooks1 = books.stream().distinct().collect(Collectors.toList());
System.out.println(distinctNameBooks1);
总结:通过重写equals和hashCode方法,按实际需求来比较,可直接使用stream的distinct方法去重,比较方便;有时对象类不方便或者不能修改,如它已实现好或者是引用的三方包不能修改,该方法不能灵活地按字段来去重。
一个字段去重
List<ProjectInfoVo> vo = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ProjectInfoVo.class));
ArrayList<ProjectInfoVo> collect = vo.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(
Comparator.comparing(p -> p.getProjectId()))), ArrayList::new));
多个字段去重
List<ProjectInfoVo> vo = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(ProjectInfoVo.class));
ArrayList<ProjectInfoVo> collect = vo.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(
Comparator.comparing(p -> p.getProjectId()+";"+p.getMember()))), ArrayList::new));
总结:
使用stream流提供的方法,代码很简洁,但不足是虽然实现了去重效果,但list里的顺序变化了,而有的场景需要保持顺序。
自定义方法类——distinctByKey
public class StreamUtils {
public 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;
}
}
单个字段
List<ProjectInfoVo> acceptances = vo.stream()
.filter(StreamUtils.distinctByKey(b -> b.getProjectId()))
.collect(Collectors.toList());
多个字段
List<ProjectInfoVo> acceptances = vo.stream()
.filter(StreamUtils.distinctByKey(b -> b.getProjectId()))
.filter(StreamUtils.distinctByKey(b -> b.getMember()))
.collect(Collectors.toList());
总结:通过封装定义一个去重方法,配合filter方法可灵活的按字段去重,保持了原列表的顺序,不足之处是内部定义了一个HashMap,有一定内存占用,并且多了一个方法定义。
Map<Object, Boolean> map = new HashMap<>();
List<Book> distinctNameBooks4 = books.stream().filter(i -> map.putIfAbsent(i.getName(), Boolean.TRUE) == null).collect(Collectors.toList());
System.out.println(distinctNameBooks4);
总结:仍然是配合filter方法实现去重,没有单独创建方法,临时定义一个HashMap,保持了原列表的顺序,不足之处是有一定内存占用。