【问题标题】:Java List with Objects - find and replace (delete) entry if Object with certain attribute already existsJava List with Objects - 如果具有特定属性的对象已经存在,则查找并替换(删除)条目
【发布时间】:2011-01-29 01:04:46
【问题描述】:

我一整天都在工作,但不知怎的,我无法解决这个可能很容易的任务 - 可能是缺少咖啡......

我有一个synchronizedList,其中存储了一些对象。这些对象有一个field,它类似于一个ID。这些对象携带有关用户及其当前状态的信息(简化版)。

重点是,我只想为每个用户提供一个对象。因此,当此用户的状态发生变化时,我想删除“旧”条目并在 List 中存储一个新条目。

protected static class Objects{
    ...
    long time;
    Object ID;
    ... 
    }

...

if (Objects.contains(ID)) {
            Objects.remove(ID);
            Objects.add(newObject);
        } else {
            Objects.add(newObject);
        }

显然这不是要走的路,但应该说明我在寻找什么...
也许数据结构不是最好的,但欢迎任何帮助!


编辑:
添加了一些信息...
Set 似乎并不真正符合我的目的。 Objects 存储除了 ID 之外的一些其他字段,这些字段一直在变化。目的是,该列表将以某种方式代表用户的最新活动。我只需要跟踪最后一个状态,并且只保留描述这种情况的那个对象。
我想我会尝试用Map 重新安排我的代码,看看是否可行......

【问题讨论】:

  • 是的,Set 的 add 方法在您的情况下是个问题。祝地图好运!
  • 谢谢,它就像一个魅力 - HashMap 上的“伪迭代”有点不确定,但效果也很好:-)

标签: java list collections object contains


【解决方案1】:

Map 是最简单的,但 Set 可以更好地反映您的逻辑。在这种情况下,我建议使用 Set。

有两种使用集合的方法,具体取决于数据对象的 equals 和 hashCode。

如果 YourObject 已经使用 ID 对象来确定 equals(并且 hashCode 遵守约定),您可以使用任何您想要的 Set,那么 HashSet 可能是最好的。

如果 YourObjects 业务逻辑需要不同的等号,考虑到 ID 字段旁边的多个字段,则应使用自定义比较器。 TreeSet 是一个可以使用这种 Comparator 的 Set。

一个例子:

Comparator<MyObject> comp = new Comparator<MyObject>{
  public int compare(MyObject o1, MyObject o2) {
    // NOTE this compare is not very good as it obeys the contract but
    // is not consistent with equals. compare() == 0 -> equals() != true here
    // Better to use some more fields
    return o1.getId().hashCode() < o2.getId().hashCode();
  }
  public boolean equals(Object other) {
    return 01.getId().equals(o2.getId());
  }
}

Set<MyObject> myObjects = new TreeSet(comp);

编辑 正如问题所建议的那样,我已经更新了上面的代码以反映 id 不是 int 。

【讨论】:

  • 为什么要使用对象的哈希码进行比较?这是错误的。
【解决方案2】:

您可以使用带有 ID 键和 Objects 值的 HashMap(或 LinkedHashMap/TreeMap,如果顺序很重要)。使用泛型HashMap&lt;Object, Objects&gt;();

然后就可以使用了

if (map.containsKey(ID)) {
    map.remove(ID);
}

map.put(newID, newObject);

或者,您可以继续使用 List,但我们不能在迭代时只修改集合,因此我们可以使用迭代器删除现有项目,然后在循环外添加新项目(现在你确定旧物品已经不见了):

List<Objects> syncList = ...

for (Iterator<Objects> iterator = syncList.iterator(); iterator.hasNext();) {
    Objects current = iterator.next();

    if (current.getID().equals(ID)) {
        iterator.remove();
    }
}

syncList.add(newObject);

【讨论】:

    【解决方案3】:

    我的第一个选项是 HashSet,这需要您覆盖 hashCode 和 equals 方法(不要忘记:如果您覆盖一个,始终覆盖另一个!)以便具有相同 ID 字段的对象被视为相等。

    但是,如果在您的应用程序的其他部分不进行此假设,这可能会破坏某些内容。在这种情况下,您可能会选择使用 HashMap(以 ID 作为键)或实现您自己的 MyHashSet 类(由此类 HashMap 支持) )。

    【讨论】:

    • 如果你真的需要一个 Set 也可以使用带有比较器的 TreeSet,它可能更适合模型。
    【解决方案4】:

    您可以使用HashSet 来存储对象,然后覆盖HashSet 将包含的类中的hashCode 方法以返回您的标识字段的哈希码。

    【讨论】:

      【解决方案5】:

      您不能使用Set 只存储第一个吗?

      因为它基本上正是您所需要的。

      【讨论】:

      • 如果一个Objects实例有其他属性(除了ID),那么他不需要存储第一个,而是最新的具有相同ID值的。
      猜你喜欢
      • 2016-05-03
      • 1970-01-01
      • 2021-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-17
      • 1970-01-01
      相关资源
      最近更新 更多