Java 8 :如何在Java 8中优雅地删除基于内部对象ID和日期的冗余外部对象?



有一个ObjectOutside,它包含另一个名为ObjectInside的对象,它有一个ID。我们需要删除具有重复 ObjectInner ID 的冗余对象外层。(我们在图片中还有另一个DateFinish对象(

public static List<ObjectOuter> removeRedundantObject(List<ObjectOuter> ObjectOuterOriginal){
if(ObjectOuterOriginal.size() == 1) {
return ObjectOuterOriginal;
}
List<ObjectInner> allObjectInner = ObjectOuterOriginal.stream().map(ObjectOuter::getObjectInner).collect(toList());
List<Long> allObjectInnerIds = allObjectInner.stream().map(ObjectInner::getObjectInnerId).collect(toList());
List<ObjectOuter> myFinalObjectOuter = new ArrayList<>();
if(ObjectOuterOriginal.size() == allObjectInnerIds.stream().distinct().collect(Collectors.toList()).size()){
return ObjectOuterOriginal;
}
Set<Long> duplicateObjectOuter = CommonUtils.getDuplicateNumbers(allObjectInnerIds); //Returns numbers which are duplicate in set
if(SetUtils.emptyIfNull(duplicateObjectOuter).isEmpty()){
return ObjectOuterOriginal;
} else {
duplicateObjectOuter.forEach((objectInnerId) -> {
List<ObjectOuter> myOwnObjectOuter = ObjectOuterOriginal.stream().filter(d -> d.getObjectInner().getObjectInnerId().equals(objectInnerId) && d.getDateFinish()==null).collect(Collectors.toList());
if(ListUtils.emptyIfNull(myOwnObjectOuter).isEmpty()) {
LocalDate maxDate = ObjectOuterOriginal.stream().filter(d -> d.getObjectInner().getObjectInnerId().equals(objectInnerId) && d.getDateFinish()!=null).map(u -> u.getDateFinish()).max(LocalDate::compareTo).get();
List<ObjectOuter> ownObjectOuter = ObjectOuterOriginal.stream().filter(d -> d.getObjectInner().getObjectInnerId().equals(objectInnerId) && d.getDateFinish()!=null).filter(d -> d.getDateFinish().compareTo(maxDate) == 0).collect(toList());
myFinalObjectOuter.addAll(ownObjectOuter);
} else {
myFinalObjectOuter.addAll(myOwnObjectOuter);
}
});
duplicateObjectOuter.forEach((objectInnerId) -> {
ObjectOuterOriginal.removeIf(d -> d.getObjectInner().getObjectInnerId().compareTo(objectInnerId) == 0);
});
ObjectOuterOriginal.addAll(myFinalObjectOuter);
}
return ObjectOuterOriginal;
}

此外,我们需要在 innerObject 上使用过滤器来仅选择那些日期为 NULL 或在重复元素中具有最大日期的 id;其中日期位于外部对象中。

上面的代码执行正常,但建议在Java 8中以更优雅的方式处理它。我只能想到先省略if语句。但是对于上面的代码片段,Java-8 中是否有合并语句的范围?

您可以使用流的过滤方法。

Set<Long> ids = new HashSet<>();
// Note: add returns true if element was not in the set
// so first occurrence will pass through filter,
// subsequent duplicates will be filtered out. 
return ObjectOuterOriginal.stream()
.filter( o -> ids.add(o.getObjectInner().getObjectInnerId()) )
.collect( Collections.toList() );

是的,这是筛选器调用中的有状态操作,因此可能被认为是"错误形式",但它可以完成工作,简短、简单、快速且易于理解。

如果您的 ID 已经是唯一的,您可以简单地执行以下操作:

public static void main(String[] args) {
Outer[] outers = {
new Outer(new Inner("a")),
new Outer(new Inner("b")),
new Outer(new Inner("c")),
new Outer(new Inner("a")),
new Outer(new Inner("b")),
new Outer(new Inner("c")),
};
Map<String, Outer> OutersById = Arrays.stream(outers).collect(Collectors.toMap(outer -> outer.inner.id, outer -> outer));
OutersById.forEach((k,v)->System.out.println(k+", "+v));
}

但这会导致重复键异常。

为了管理您的重复项,并使用您自己的消除歧义策略,

Map<String, Outer> OutersById = Arrays.stream(outers).collect(Collectors.toMap(outer -> outer.inner.id, outer -> outer));

可以更改为

Map<String, Outer> OutersById = Arrays.stream(outers)
.collect(
Collectors.toMap(
outer -> outer.inner.id, 
outer -> outer,
(a, b) -> a.hashCode() > b.hashCode() ? a : b
));

或者您想要的任何其他策略,也许外部有一个可以比较的日期?

也许 a 和 b 可以连接成一个新的对象 ab?

更新:

public static void main(String[] args) {
Instant now = Instant.now();
Instant nxtWeek= now.plus(Duration.ofDays(7));
Outer[] outers = {
new Outer(new Inner("a"), null),
new Outer(new Inner("b"), Date.from(now)),
new Outer(new Inner("c"), Date.from(nxtWeek)),
new Outer(new Inner("a"), Date.from(now)),
new Outer(new Inner("b"), Date.from(nxtWeek)),
new Outer(new Inner("c"), null),
};
Comparator<Outer> outerRanker = Comparator.comparing(Outer::getFinishDate, Comparator.nullsLast(Date::compareTo));
Map<String, Outer> OutersById = Arrays.stream(outers)
.collect(
Collectors.toMap(
outer -> outer.inner.id,
outer -> outer,
(a, b) -> outerRanker.compare(a,b) > 0 ? a : b
));
System.out.println("today: "+Date.from(now));
OutersById.forEach((k,v)->System.out.println(k+", "+v));
}

结果在

today: Thu Jun 07 15:11:12 ACST 2018
a, Outer{inner=Inner{id='a'}, FinishDate=null}
b, Outer{inner=Inner{id='b'}, FinishDate=Thu Jun 14 15:11:12 ACST 2018}
c, Outer{inner=Inner{id='c'}, FinishDate=null}
Process finished with exit code 0

最新更新