Google Guava与哈希操作相关的类

文章目录

  • 1.概述
  • 2.组成
    • 2.1HashFunction
    • 2.2Hasher
    • 2.3Funnel
    • 2.4HashCode
  • 3.BloomFilter
  • 4.Hashing
    • 4.1提供的哈希函数
    • 4.2HashCode操作

哈希:比Object.hashCode()提供的更复杂的哈希工具,包括布隆过滤器。

1.概述

Java固有的哈希码概念被限制为32位,并且在哈希算法和它们所作用的数据之间没有分隔,因此替代的哈希算法不容易被替换。同样,hashCode的实现往往质量较差,部分原因是它们最终依赖于其他现有的质量较差的hashCode实现,包括许多JDK类中的实现。

Object.hashCode实现通常非常快,但是具有较弱的冲突预防功能,并且不期望出现位分散。这使它们非常适合在哈希表中使用,因为额外的冲突只会对性能造成轻微的影响,而不良的位分散则可以使用辅助哈希函数(使用Java中所有合理的哈希表实现)轻松纠正。然而,对于哈希函数在简单哈希表之外的许多用途,Object.hashCode几乎总是不足——因此有了com.google.common.hash

2.组成

在查看Javadoc包时,我们看到了许多不同的类型,但是它们如何组合在一起并不明显。

让我们来看一段使用该库的示例代码。

HashFunction hf = Hashing.md5();
HashCode hc = hf.newHasher()
       .putLong(id)
       .putString(name, Charsets.UTF_8)
       .putObject(person, personFunnel)
       .hash();

2.1HashFunction

HashFunction是一个纯无状态函数,它将任意数据块映射到固定数量的位,其属性是相等的输入始终产生相等的输出,而不相等的输入则尽可能每次产生不相等的输出。

2.2Hasher

可以向HashFunction请求有状态的Hasher,它提供了流利的语法以将数据添加到哈希中,然后检索哈希值。Hasher可以接受任何原生输入、字节数组、字节数组的片段、字符序列、某些字符集中的字符序列等,或任何其他带有合适的FunnelObject

Hasher实现了PrimitiveSink接口,该接口为接受原生值流的对象指定了流利的API。

2.3Funnel

Funnel描述了如何将特定的对象类型分解为原生字段值。例如,如果我们有

class Person {
  final int id;
  final String firstName;
  final String lastName;
  final int birthYear;
}

我们的Funnel看起来像

Funnel<Person> personFunnel = new Funnel<Person>() {
  @Override
  public void funnel(Person person, PrimitiveSink into) {
    into
        .putInt(person.id)
        .putString(person.firstName, Charsets.UTF_8)
        .putString(person.lastName, Charsets.UTF_8)
        .putInt(birthYear);
  }
};

注意putString("abc", Charsets.UTF_8).putString("def", Charsets.UTF_8)完全等效于putString("ab", Charsets.UTF_8).putString("cdef", Charsets.UTF_8),因为它们产生了相同的字节序列。这可能会导致意外的哈希冲突。添加某种分隔符可以帮助消除意外的哈希冲突。

2.4HashCode

一旦为Hasher提供了所有输入,就可以使用其hash()方法检索HashCodeHashCode支持相等性测试等,以及asInt()asLong()asBytes()方法,还支持writeBytesTo(array, offset, maxLength),它将哈希的第一个maxLength字节写入数组。

3.BloomFilter

布隆过滤器是一个很好的哈希应用程序,不能简单地使用Object.hashCode()来完成。简而言之,布隆过滤器是一种概率数据结构,可让你测试某个对象是否绝对不在过滤器中,或者可能已添加到Bloom过滤器中。维基百科页面非常全面,我们推荐使用本教程。

我们的哈希库具有内置的布隆过滤器实现,只需要你实现一个Funnel即可将你的类型分解为原生类型。你可以使用create(Funnel funnel, int expectedInsertions, double falsePositiveProbability)获得新的BloomFilter,或者只接受默认的3%错误概率。BloomFilter提供了方法boolean mightContain(T)void put(T),这已经不言而喻了。

BloomFilter<Person> friends = BloomFilter.create(personFunnel, 500, 0.01);
for (Person friend : friendsList) {
  friends.put(friend);
}
// much later
if (friends.mightContain(dude)) {
  // the probability that dude reached this place if he isn't a friend is 1%
  // we might, for example, start asynchronously loading things for dude while we do a more expensive exact check
}

4.Hashing

Hashing工具类提供了许多用于对HashCode对象进行操作的签名哈希函数和工具。

4.1提供的哈希函数

  • md5()
  • murmur3_128()
  • murmur3_32()
  • sha1()
  • sha256()
  • sha512()
  • goodFastHash(int bits)

4.2HashCode操作

方法 描述
HashCode combineOrdered(Iterable) 以有序方式组合哈希码,因此,如果从此方法获得的两个哈希相同,则很可能每个哈希都是以相同的顺序从相同的哈希中计算得出的。
HashCode combineUnordered(Iterable) 以无序方式组合哈希码,因此,如果从此方法获得的两个哈希相同,则很可能每个哈希都是以相同的顺序从相同的哈希中计算得出的。
int consistentHash(HashCode, int buckets) 为哈希码分配一个一致的“桶”,这样可以最大限度地减少随着bucket桶数量的增加而重新映射的需要。有关详细信息,请参见维基百科。

本文参考:
HashingExplained
guava-tests-hash

你可能感兴趣的:(Google,Guava)