Java 8使用流来区分具有重复字段值的对象

时间:2018-12-03 15:19:51

标签: java filter java-8 java-stream

我有一个对象列表。每个对象都有三个字段:idsecNumbertypeType是枚举,可以具有值'new'或'legacy'。有时会发生该列表中的某些对象具有相同的secNumber a但类型不同的情况。

在这种情况下,我需要删除“ legacy”类型的那个。如何使用Java 8流实现?

2 个答案:

答案 0 :(得分:3)

toMap与以下内容一起使用:

Collection<T> result = list.stream()
    .collect(toMap(T::getSecNumber, 
            Function.identity(), 
             (l, r) -> l.getType() == Type.LEGACY ? r : l))
    .values();

其中T是包含secNumberid等的类。

  • keyMapperT::getSecNumber)从每个对象中提取每个secNumber
  • valueMapperFunction.identity())提取我们想要的对象作为地图值,即从源中获取的对象。
  • mergeFunction (l, r) ->是我们说的“如果两个给定对象具有相同的键,即getSecNumber,则将其保留为类型为'NEW'的对象,并使用' LEGACY'”,最后我们调用values()将地图值累积到Collection中。

修改:

您可能正在关注@Tomer Aberbach的评论:

List<T> result = 
            list.stream()
                .collect(groupingBy(T::getSecNumber))
                .values()
                .stream()
                .flatMap(l -> l.stream().anyMatch(e -> e.getType() == Type.NEW) ?
                    l.stream().filter(e -> e.getType() != Type.LEGACY) :
                    l.stream())
                .collect(toList());

第一个使用toMap的解决方案假定不能有多个对象具有相同的secNumbertype

答案 1 :(得分:3)

假设objects是已经声明和初始化的List<ClassName>

List<ClassName> filteredObjects = objects.stream()
    .collect(Collectors.groupingBy(ClassName::getSecNumber))
    .values().stream()
    .flatMap(os -> os.stream().anyMatch(o -> o.getType() == Type.NEW) ?
        os.stream().filter(o -> o.getType() != Type.LEGACY) :
        os.stream()
    ).collect(Collectors.toList());

我假设Type.LEGACY类型的对象仅应在存在另一个Type.NEW类型的secNumber类型对象的情况下才被过滤掉。我还假设您可能具有相同typesecNumber的多个对象,并且可能需要保留这些对象。

请注意,collect(Collectors.groupingBy(ClassName::getSecNumber))返回的映射类型是secNumberList<ClassName>的类型,因此在其上调用values()会返回Collection<List<ClassName>>,它表示具有相同secNumber的对象分组。

flatMap部分按secNumber进行每个分组,检查分组中是否至少有一个Type.NEW对象,如果有,则过滤掉{{1}类型的对象},否则它只会沿着要展平的对象传递到最终的Type.LEGACY中。这样做的主要目的是,如果一个分组中只有List<ClassName>类型的对象,那么它们就不会被排除在最终集合之外。