列表的 Java 流差异



我有一类带有字段日期、ID 和操作的 Item。就我而言,我有旧项目列表和另一个列表,其中包括旧项目和新项目,所以我想过滤掉旧项目,所以我不会介意它们。例如,我遍历新项目,只使用不属于旧项目列表的项目。

使用 for 循环,它看起来像这样,但我想重写它的功能方式

List<Item> filteredList = new ArrayList<>();
for (Item item : newList) {
for (Item oldItem : oldList) {
if (!item.getDate().equals(oldItem.getDate()) && !item.getId().equals(oldItem.getId()) && !item.getAction().equals(oldItem.getAction())) {
filteredList.add(item);
}
}
}

首先,我建议在Item类中实现一个equals方法,以避免这种复杂的情况(我不确定是否正确,顺便说一句(。

其次,为了使搜索更有效率,将旧列表的元素放在一个HashSet中,以允许恒定的时间查找。这将需要覆盖Item类的equalshashCode

最后,代码将如下所示:

List<Item> filteredList = 
newList.stream()
.filter(i -> !oldList.contains(i)) // oldList should be replaced with a HashSet 
// for better performance
.collect(Collectors.toList());

HashSet

Set<Item> oldSet = new HashSet<>(oldList);
List<Item> filteredList = 
newList.stream()
.filter(i -> !oldSet.contains(i)) 
.collect(Collectors.toList());

关于您的病情:

if (!item.getDate().equals(oldItem.getDate()) && !item.getId().equals(oldItem.getId()) && !item.getAction().equals(oldItem.getAction()))

这似乎是错误的,因为如果具有不同 ID 的两个项目将具有相同的日期(或操作(,它们将无法通过测试。

我相信你打算写:

if (!item.getDate().equals(oldItem.getDate()) || !item.getId().equals(oldItem.getId()) || !item.getAction().equals(oldItem.getAction()))

这意味着,如果两个项在 3 个属性中的至少一个属性上不同,则认为它们彼此不同。

首先,你应该在Item类中实现equals()方法(以及.hashCode()(,以便你可以正确地比较项目,例如,使用List.contains()方法时将需要它。

然后,您可以使用.contains()方法来测试当前项是否存在于oldList中,并根据该结果筛选项。

在 Java 8 中,您的代码应如下所示:

List<Item> result = newList.stream()                
.filter(line -> !oldList.contains(line))    
.collect(Collectors.toList());

注意:

请注意,此处使用stream并不是真正必要的,因为您可以使用List方法来实现这一点,例如.retainAll()这将允许您以更好的方式过滤newList

此任务不需要流。只需使用List.removeAll方法,它就可以完全按照您的要求:

oldList.removeAll(newList);

这要求Item类实现equals()方法,以便可以比较元素的相等性并删除。

如果您不想更改原始oldList,则可以创建一个新列表,然后从中删除元素:

List<Item> filteredList = new ArrayList<>(oldList);
filteredList.removeAll(newList);

另一种更实用的方法是使用Collection.removeIf方法:

oldList.removeIf(item -> newList.contains(item));

或者只是:

oldList.removeIf(newList::contains);

这仍然需要Item类来实现equals()方法。但是,它也是低效的,因为List.contains需要遍历整个newList来检查每个oldList项目是否属于它。更有效的方法是使用HashSet

Set<Item> newSet = new HashSet<>(newList);

然后,使用上述removeIf

oldList.removeIf(newSet::contains);

这种方法不仅要求Item类实现equals()方法,还要求hashCode方法,该方法必须符合Object类关于相等的契约。

相关内容

  • 没有找到相关文章

最新更新