Stream流去重问题

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());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值