Java:记住处理了哪些对象的有效方法

Java: efficient way to remember which objects are processed

记住处理了哪些对象的最有效方法是什么?

显然可以使用哈希集:

Set<Foo> alreadyProcessed = new HashSet<>();

void process(Foo foo) {
    if (!alreadyProcessed.contains(foo)) {
        // Do something
        alreadyProcessed.add(foo);
    }
}

这让我想知道为什么我要存储对象,而我只是想检查该集合中是否存在散列。假设 foo 的任何散列都是唯一的。

有没有更高效的方法来做到这一点?

请记住,将处理大量对象,实际处理代码并不总是很繁重。我也不可能有对象的预编译工作列表,它将在处理过程中动态构建。

写出好的代码。仅当您可以证明在您的用例中需要这样做时,才针对性能对其进行优化。

存储哈希码而不是对象没有性能优势。如果您对此表示怀疑,请记住存储的是对象的 reference,而不是对象的副本。实际上这将是 64 位,与哈希码几乎相同。您已经花费了大量时间思考 none 用户会注意到的问题。 (如果您在紧密的任务关键型循环中进行数百万次此计算,那就另当别论了)。

使用集合简单易懂。做任何其他事情都有可能导致未来的维护者无法理解代码并引入错误。

另外不要忘记哈希码不能保证对每个不同的对象都是唯一的。经常存储哈希码会给你一个误报,导致你无法处理你想要处理的对象。 (顺便说一句,你需要确保 equals() 只认为两个对象相等,如果它们是同一个对象。默认的 Object.equals() 会这样做,所以不要覆盖它)

使用套装。如果您正在处理大量对象,请使用比 HashSet 更高效的 Set。这比使用散列的任何巧妙方法更有可能给您带来性能加速。

您不能使用哈希码,因为两个对象的哈希码相等并不意味着这两个对象相等。

否则取决于你想记住的用例,如果你已经处理过

  • a) 相同的对象,通过引用测试,或
  • b) 一个相等的对象,通过调用 Object.equals(Object)
  • 进行测试

对于 b),您可以使用标准 Set 实现。

对于 a) 如果您现在 equals 方法返回引用相等,您也可以使用标准 Set 实现,或者您需要类似 IdentityHashSet.[= 的东西14=]

此答案中未提及性能,您需要先解决正确性问题!

  1. Set#contains可以非常快。这取决于您的 hashcode()equals() 方法是如何实现的。尝试缓存 哈希码值 以使其更快。 (喜欢String.java)

  2. 另一个简单快捷的选项是向您的 Foo 添加一个布尔成员 class:foo.done = true;