概述

Java内建的散列码[hash code]概念被限制为32位,并且没有分离散列算法和它们所作用的数据,因此很难用备选算法进行替换。此外,使用Java内建方法实现的散列码通常是劣质的,部分是因为它们最终都依赖于JDK类中已有的劣质散列码。

Object.hashCode往往很快,但是在预防碰撞上却很弱,也没有对分散性的预期。这使得它们很适合在散列表中运用,因为额外碰撞只会带来轻微的性能损失,同时差劲的分散性也可以容易地通过再散列来纠正(Java中所有合理的散列表都用了再散列方法)。然而,在简单散列表以外的散列运用中,Object.hashCode几乎总是达不到要求——因此,有了com.google.common.hash包。

散列包的组成

在这个包的Java doc中,我们可以看到很多不同的类,但是文档中没有明显地表明它们是怎样 一起配合工作的。在介绍散列包中的类之前,让我们先来看下面这段代码范例:

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

HashFunction

HashFunction是一个单纯的(引用透明的)、无状态的方法,它把任意的数据块映射到固定数目的位指,并且保证相同的输入一定产生相同的输出,不同的输入尽可能产生不同的输出。

Hasher

HashFunction的实例可以提供有状态的Hasher,Hasher提供了流畅的语法把数据添加到散列运算,然后获取散列值。Hasher可以接受所有原生类型、字节数组、字节数组的片段、字符序列、特定字符集的字符序列等等,或者任何给定了Funnel实现的对象。

Hasher实现了PrimitiveSink接口,这个接口为接受原生类型流的对象定义了fluent风格的API

Funnel

Funnel描述了如何把一个具体的对象类型分解为原生字段值,从而写入PrimitiveSink。比如,如果我们有这样一个类:

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),因为它们提供了相同的字节序列。这可能带来预料之外的散列冲突。增加某种形式的分隔符有助于消除散列冲突。

HashCode

一旦Hasher被赋予了所有输入,就可以通过hash()方法获取HashCode实例(多次调用hash()方法的结果是不确定的)。HashCode可以通过asInt()asLong()asBytes()方法来做相等性检测,此外,writeBytesTo(array, offset, maxLength)把散列值的前maxLength字节写入字节数组。

布鲁姆过滤器[BloomFilter]

布鲁姆过滤器是哈希运算的一项优雅运用,它可以简单地基于Object.hashCode()实现。简而言之,布鲁姆过滤器是一种概率数据结构,它允许你检测某个对象是一定不在过滤器中,还是可能已经添加到过滤器了。布鲁姆过滤器的维基页面对此作了全面的介绍,同时我们推荐github中的一个教程

Guava散列包有一个内建的布鲁姆过滤器实现,你只要提供Funnel就可以使用它。你可以使用create(Funnel funnel, int expectedInsertions, double falsePositiveProbability)方法获取BloomFilter<T>,缺省误检率[falsePositiveProbability]为3%。BloomFilter<T>提供了boolean mightContain(T) 和void put(T),它们的含义都不言自明了。

BloomFilter<Person> friends = BloomFilter.create(personFunnel, 500, 0.01);
for(Person friend : friendsList) {
friends.put(friend);
} // 很久以后
if (friends.mightContain(dude)) {
//dude不是朋友还运行到这里的概率为1%
//在这儿,我们可以在做进一步精确检查的同时触发一些异步加载
}

Hashing类

Hashing类提供了若干散列函数,以及运算HashCode对象的工具方法。

已提供的散列函数

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

HashCode运算

方法 描述
HashCode combineOrdered( Iterable<HashCode>) 以有序方式联接散列码,如果两个散列集合用该方法联接出的散列码相同,那么散列集合的元素可能是顺序相等的
HashCode   combineUnordered( Iterable<HashCode>) 以无序方式联接散列码,如果两个散列集合用该方法联接出的散列码相同,那么散列集合的元素可能在某种排序下是相等的
int   consistentHash( HashCode, int buckets) 为给定的”桶”大小返回一致性哈希值。当”桶”增长时,该方法保证最小程度的一致性哈希值变化。详见一致性哈希

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: [Google Guava] 10-散列

Guava 10-散列的更多相关文章

  1. HashMap,Hash优化与高效散列

    OverView Hash table based implementation of the Map interface. This implementation provides all of t ...

  2. Redis命令拾遗二(散列类型)

    本文版权归博客园和作者吴双共同所有,欢迎转载,转载和爬虫请注明原文地址 :博客园蜗牛NoSql系列地址  http://www.cnblogs.com/tdws/tag/NoSql/ Redis命令拾 ...

  3. javascript数据结构与算法--散列

    一:javascript数据结构与算法--散列  一:什么是哈希表? 哈希表也叫散列表,是根据关键码值(key,value)而直接进行访问的数据结构,它是通过键码值映射到表中一个位置来访问记录的,散列 ...

  4. 数据结构和算法 – 7.散列和 Hashtable 类

    7.1.散列函数 散列是一种常见的存储数据的技术,按照这种方式可以非常迅速地插入和取回数据.散列所采用的数据结构被称为是散列表.尽管散列表提供了快速地插入.删除.以及取回数据的操作,但是诸如查找最大值 ...

  5. 线性探测再散列 建立HASH表

    根据数据元素的关键字和哈希函数建立哈希表并初始化哈希表,用开放定址法处理冲突,按屏幕输出的功能表选择所需的功能实现用哈希表对数据元素的插入,显示,查找,删除. 初始化哈希表时把elem[MAXSIZE ...

  6. oracle的散列聚簇表

    在簇表中,Oracle使用存储在索引中的键值来定位表中的行, 而在散列聚簇表中,使用了散列函数代替了簇索引,先通过内部函数或者自定义的函数进行散列计算,然后再将计算得到的码值用于定位表中的行. 创建散 ...

  7. s14 第5天 时间模块 随机模块 String模块 shutil模块(文件操作) 文件压缩(zipfile和tarfile)shelve模块 XML模块 ConfigParser配置文件操作模块 hashlib散列模块 Subprocess模块(调用shell) logging模块 正则表达式模块 r字符串和转译

    时间模块 time datatime time.clock(2.7) time.process_time(3.3) 测量处理器运算时间,不包括sleep时间 time.altzone 返回与UTC时间 ...

  8. 流畅python学习笔记:第十章:序列的修改,散列和切片

    前面在介绍了类的很多内置方法,比如__add__,__eq__,这里继续介绍类的两个内置方法,这2个内置方法可以将一个类实例变成一个序列的形式.代码如下 class vector(object):   ...

  9. PTA 字符串关键字的散列映射(25 分)

    7-17 字符串关键字的散列映射(25 分) 给定一系列由大写英文字母组成的字符串关键字和素数P,用移位法定义的散列函数H(Key)将关键字Key中的最后3个字符映射为整数,每个字符占5位:再用除留余 ...

  10. 关于Java的散列桶, 以及附上一个案例-重写map集合

    为速度而散列: SlowMap.java说明了创建一个新的Map并不困难.但正如它的名称SlowMap所示,它不会很快,如果有更好的选择就应该放弃它.它的问题在于对键的查询,键没有按照任何特定的顺序保 ...

随机推荐

  1. java的nio之:java的nio系列教程之SocketChannel

    Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道.可以通过以下2种方式创建SocketChannel: 打开一个SocketChannel并连接到互联网上的某台服务器. ...

  2. Latex 编译错误: ! pdfTeX error (ext4): \pdfendlink ended up in different nesting level than \pd fstartlink. 解决方法

    最近写 AAAI 的文章,下载了其模板,但是蛋疼的是,总是提示错误,加上参考文献总是出错: 如下: ! pdfTeX error (ext4): \pdfendlink ended up in dif ...

  3. Introduction to Monte Carlo Tree Search (蒙特卡罗搜索树简介)

    Introduction to Monte Carlo Tree Search (蒙特卡罗搜索树简介)  部分翻译自“Monte Carlo Tree Search and Its Applicati ...

  4. Linux-获取当前正在执行脚本的绝对路径

    常见的一种误区,是使用 pwd 命 令,该命令的作用是“print name of current/working directory”,这才是此命令的真实含义,当前的工作目录,这里没有任何意思说明, ...

  5. Andorid面试问题整理

    Acitivty的四中启动模式与特点. standard:默认的启动模式 singleTop:适合那种接受通知启动的页面,比如新闻客户端之类的,可能会给你推送好几次 ,但是每次都是打开同一张页面调用o ...

  6. 只显示 前100个字 java 实现截取字符串!使用! <c:if test="${fn:length(onebeans.info)>100 }">${ fn:substri

    博客 文章 只显示 前100个字 java 实现截取字符串!使用! <c:if test="${fn:length(onebeans.info)>100 }">$ ...

  7. 执行NET 命令无法使用超过20个字符的组名或用户名

    https://support.microsoft.com/en-us/kb/324639     执行 net localgroup "Performance Monitor Users& ...

  8. display模版详细介绍

    ASP.NET MVC 2 Templates, Part 4: Custom Object Templates Series Index Part 1: Introduction Part 2: M ...

  9. 必须Mark!43个优秀的Swift开源项目推荐

    摘要:拥有着苹果先天生态优势的Swift自发布以来,各种优秀的开源项目便层出不穷.本文作者站在个人的角度,将2014年Swift开源项目做了一个甄别.筛选,从工具.存储.网络.界面.框架到Demo以及 ...

  10. 解决:错误 14274: 无法添加、更新或删除 SQL 服务器上的作业的问题一例

      今天在修改 SQL服务器上 以前的作业任务,打算把作业的执行时间修改成新的时间,结果修改好点确定, 结果出现了以下错误! --------------------------- Microsoft ...