使用UUID进行廉价的equals()和hashCode()

Tom*_*yre 7 java performance equals hashcode

我有一个不可变的类TokenList,它由Token对象列表组成,它们也是不可变的:

@Immutable
public final class TokenList {

    private final List<Token> tokens;

    public TokenList(List<Token> tokens) {
        this.tokens = Collections.unmodifiableList(new ArrayList(tokens));
    }

    public List<Token> getTokens() {
        return tokens;
    }
}
Run Code Online (Sandbox Code Playgroud)

我对这些TokenLists执行了几个操作,这些操作将多个TokenLists作为输入并返回单个TokenList作为输出.可以有任意多个TokenLists进入,每个TokenLists可以有任意多个Tokens.

这些操作很昂贵,并且很有可能多次执行相同的操作(即相同的输入),所以我想缓存输出.但是,性能至关重要,我担心在这些可能包含任意多个元素的对象上执行hashCode()和equals()的费用(因为它们是不可变的,然后hashCode可以被缓存,但是equals仍然很昂贵).

这让我想知道是否可以通过对TokenList进行以下更新来简单而廉价地使用UUID来提供equals()和hashCode():

@Immutable
public final class TokenList {

    private final List<Token> tokens;
    private final UUID uuid;

    public TokenList(List<Token> tokens) {
        this.tokens = Collections.unmodifiableList(new ArrayList(tokens));
        this.uuid = UUID.randomUUID();
    }

    public List<Token> getTokens() {
        return tokens;
    }

    public UUID getUuid() {
        return uuid;
    }
}
Run Code Online (Sandbox Code Playgroud)

这样的东西充当缓存键:

@Immutable
public final class TopicListCacheKey {

    private final UUID[] uuids;

    public TopicListCacheKey(TopicList... topicLists) {
        uuids = new UUID[topicLists.length];
        for (int i = 0; i < uuids.length; i++) {
            uuids[i] = topicLists[i].getUuid();
        }
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(uuids);
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) return true;
        if (other instanceof TopicListCacheKey)
            return Arrays.equals(uuids, ((TopicListCacheKey) other).uuids);
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为有2 ^ 128个不同的UUID,我可能在任何时候最多有大约1,000,000个TokenList对象在应用程序中活动.鉴于此,以及UUID在缓存键中组合使用的事实,似乎产生错误结果的可能性非常小.尽管如此,我对它的进展感到不安,因为它感觉"很脏".有什么理由我不应该使用这个系统吗?UUID.randomUUID()使用的SecureRandom的性能成本是否会超过收益(特别是因为我希望多个线程同时执行此操作)?碰撞是否比我想象的更可能?基本上,这样做有什么不妥吗?

谢谢.

Pea*_*oto 0

SecureRandom不会给你任何提升,它只是比普通的“更”随机Random。发生冲突的几率约为该数字的平方除以可能的 UUID 总数,因此是一个非常小的数字。不过,我不会依赖这个数字总是唯一的。您可以尝试此操作,但最好检查并确保该数字尚未包含在哈希码列表中的其他位置。否则,你可能会让自己陷入一些非常奇怪的问题......