概述

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

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

散列包的组成

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

  1. HashFunction hf = Hashing.md5();
  2. HashCode hc = hf.newHasher()
  3. .putLong(id)
  4. .putString(name, Charsets.UTF_8)
  5. .putObject(person, personFunnel)
  6. .hash();

HashFunction

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

Hasher

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

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

Funnel

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

  1. class Person {
  2. final int id;
  3. final String firstName;
  4. final String lastName;
  5. final int birthYear;
  6. }

它对应的Funnel实现可能是:

  1. Funnel<Person> personFunnel = new Funnel<Person>() {
  2. @Override
  3. public void funnel(Person person, PrimitiveSink into) {
  4. into
  5. .putInt(person.id)
  6. .putString(person.firstName, Charsets.UTF_8)
  7. .putString(person.lastName, Charsets.UTF_8)
  8. .putInt(birthYear);
  9. }
  10. }

注: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),它们的含义都不言自明了。

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

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 Lambda Expressions streams

    http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html https:// ...

  2. SQLite在多线程环境下的应用

    文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...

  3. ABBYY PDF Transformer+ Pro支持全世界189种语言

    ABBYY PDF Transformer+ Pro版支持189种语言,包括我们人类的自然语言.人造语言以及正式语言.受支持的语言可能会因产品的版本不同而各异.本文具体列举了所有ABBYY PDF T ...

  4. jQuery.fn.extend与jQuery.extend

    jQuery.extend(),是扩展的jQuery这个类. 假设我们把jQuery这个类看成是人类,能吃饭能喝水能跑能跳,现在我们用jQuery.extend这个方法给这个类拓展一个能唱歌的技能.这 ...

  5. C数据类型

    结构体 因为数组中各元素的类型和长度都必须一致,以便于编译系统处理.为了解决这个问题,C语言中给出了另一种构造数据类型——“结构(structure)”或叫“结构体”.它相当于其它高级语言中的记录.“ ...

  6. 创建对象的最好方式&最好的继承机制(代码实例)

    /* 创建对象的最好方式:混合的构造函数/原型方式, *用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法) */ function People(sname){ this.nam ...

  7. MATLAB中trapz和cumtrapz函数

    这两个函数都是MATLAB中的内置函数,是基于梯形法则的数值积分公式 例如我们有函数y=x^3-2x-3,为了计算在[0,1]上的积分,可以这么做: 其中x和y分别是自变量和对应的值,trapz其实就 ...

  8. Hadoop学习地址

    hortonworks: http://zh.hortonworks.com/hdp/downloads/ http://zh.hortonworks.com/hadoop-tutorial/supe ...

  9. Android 网络编程--URL互联网资源

    1.加入权限 <uses-permission android:name="android.permission.INTERNET"/> 2.Layout设计 < ...

  10. svn钩子(hooks)

    首先你需要搭建出自己的svn环境出来,并能成功导入导出,并且了解svn,这是看这篇文章的前提.... 出于公司开发部需要svn同步更新服务器代码,需要用到svn钩子(hooks)技术,以前从来没听过, ...