1.根据对象的属性进行去重
(2)
@GetMapping("listAllMaterialsType")
public Result<List<Materials>> listAllMaterialsType() {
List<Materials> materials = materialsService.list(Wrappers.lambdaQuery(Materials.class));
List<Materials> distinctMaterials = CollectionUtils.isEmpty(materials) ? null :
materials.stream()
.filter(o -> ObjectUtil.isNotEmpty(o.getType()))
// 相同材料类型编码去重
.collect(collectingAndThen
(toCollection(() -> new TreeSet<>(Comparator.comparing(Materials::getType))), ArrayList::new)
);
distinctMaterials.forEach(o -> {
o.setTypeString(ProductTypeEnum.get(o.getType()).getName());
});
return Result.ok(distinctMaterials);
}
(2)自定义的distinctByKey根据对象的属性进行去重(推荐)
List<Technology> technologies = technologyService.list(Wrappers.lambdaQuery(Technology.class))
.stream()
.filter(FunctionUtil.distinctByKey(Technology::getName))
.collect(Collectors.toList());
@UtilityClass
public class FunctionUtil {
public <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> map = new ConcurrentHashMap<>(16);
return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}
-
【distinctByKey】的原理:filter方法,返回一个流,需要一个Predicate类型的参数(多嘴介绍下Predicate这个函数式接口,接受一个参数,返回布尔值)。
-
Stream filter(Predicate<? super T> predicate)
filter根据Predicate返回的布尔值来判断是否要过滤掉,会过滤掉返回值为false的数据。而我们自己定义的distinctByKey返回值就是Predicate,所以可以作为参数传入filter。 -
distinctByKey也需要一个Function的参数。distinctByKey先是定义了一个线程安全的Map(相比于Hashtable以及Collections.synchronizedMap(),ConcurrentHashMap在线程安全的基础上提供了更好的写并发能力,但同时降低了对读一致性的要求),因为在流计算中是多线程处理的,需要线程安全。
-
然后将值作为key,TRUE作为value put到map中。这里的put方法使用的是putIfAbsent()。putIfAbsent()方法是如果key不存在则put如map中,并返回null。若key存在,则直接返回key所对应的value值。
其中putIfAbsent方法如下:
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
所以
seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
这里用 == null判断是否存在于map了,若存在则返回false,不存在则为true。以用来达到去重的目的。
注:putIfAbsent()定义在Map接口中,是默认方法。
2.合并集合,对集合中的对象进行去重
List<String> technologyNames1 = new ArrayList<>();
List<String> technologyNames2 = new ArrayList<>();
List<String> technologyNames3 = new ArrayList<>();
if (ObjectUtil.isNotEmpty(boxDTO.getTechnologyNames1())) {
technologyNames1 = boxDTO.getTechnologyNames1();
}
if (ObjectUtil.isNotEmpty(boxDTO.getTechnologyNames2())) {
technologyNames2 = boxDTO.getTechnologyNames1();
}
if (ObjectUtil.isNotEmpty(boxDTO.getTechnologyNames3())) {
technologyNames3 = boxDTO.getTechnologyNames1();
}
List<String> technologyNames = Stream.of(technologyNames1, technologyNames2, technologyNames3)
.flatMap(Collection::stream)
.distinct()
.filter(ObjectUtil::isNotEmpty)
.collect(Collectors.toList());