有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

列表的Java流差异

我有一个包含日期、id和操作字段的项类。在我的例子中,我有一个旧项目列表和另一个列表,其中包括旧项目和新项目,所以我想过滤掉旧项目,这样我就不会介意它们了。例如,我迭代新项目,只使用不属于旧项目列表的项目

对于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);
            }
        }
    }

共 (3) 个答案

  1. # 1 楼答案

    首先,我建议在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个属性中至少有一个不同,则认为它们彼此不同

  2. # 2 楼答案

    此任务不需要流。只需使用^{}方法即可,该方法完全满足您的要求:

    oldList.removeAll(newList);
    

    这需要Item类来实现equals()方法,这样就可以比较元素的相等性并将其删除

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

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

    另一种更实用的ish方法是使用^{}方法:

    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类契约

  3. # 3 楼答案

    首先,您应该在Item类中实现equals()方法(以及.hashCode()),这样您就可以正确地比较项目,例如,在使用List^{} method时需要它

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

    使用Java 8时,您的代码应如下所示:

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

    注意:

    请注意,这里使用stream并不是真正必要的,因为您可以通过使用List方法来实现这一点,例如^{},它将允许您以更好的方式过滤newList