[Google Guava] 10-散列

原文链接 译文链接 译者:沈义扬

概述

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

时间: 2024-11-02 19:38:29

[Google Guava] 10-散列的相关文章

Google Guava官方教程(中文版)

原文链接  译文链接 译者: 沈义扬,罗立树,何一昕,武祖  校对:方腾飞 引言 Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] .缓存 [caching] .原生类型支持 [primitives support] .并发库 [concurrency libraries] .通用注解 [common annotations] .字符串处理 [string processing] .I/O 等等. 所有这些工具每天都在被Google

10年商标纠纷落幕西南药业终获“散列通”

每经记者 肖晓芬 发自上海 西南药业与瑞士罗氏公司一场关于"散利痛"."散列通"长达10年的商标纠纷终于落下帷幕.日前,西南药业(600666,SH)拿到了最高人民法院的终审判决书,该判决维持国家工商总局商标评审委员会关于"散列通"商标有效的裁定,西南药业最终胜诉. 10年商标之争落幕 散列通商标纠纷案源于上世纪.据公开资料显示,1987年,瑞士罗氏公司为了让其产品散利痛进入 中国市场,与西南药业(当时名称为西南制药三厂)签订了"关于'

Google发布CityHash系列散列算法

Google发布了 CityHash系列字符串散列算法.今天发布的有两种算法:CityHash64 与 CityHash128.它们分别根据字串计算64和128位的散列值.这些算法不适用于加密,但适合用在散列表等处. Google一直在根据其数据中心常用的CPU对算法进行优化,结果发现对大多数个人计算机与笔记本同样有效益.尤其是在64位寄存器.指令集级的并行,以及快速非对其内存存取方面. 该算法的开发受到了前人在散列算法方面的巨大启发,尤其是Austin Appleby的MurmurHash.但

[Google Guava] 1.3-常见Object方法

原文链接 译者: 沈义扬 equals 当一个对象中的字段可以为null时,实现Object.equals方法会很痛苦,因为不得不分别对它们进行null检查.使用Objects.equal帮助你执行null敏感的equals判断,从而避免抛出NullPointerException.例如: 1 Objects.equal("a", "a"); // returns true 2 Objects.equal(null, "a"); // retur

PHP大量Session的散列及过期回收

一台服务器流量比较大,因为程序的需要,session的过期时间设置的是3小时,导致/tmp下堆积了近20万的session文件.进而导致内核占用的cpu急剧上升.因为session的读写涉及到大量小文件的随机读写,并且是集中在一个目录下,iowait也急剧升高. 首先考虑将session放入内存中 最简单的办法莫过于将/tmp挂载为 tmpfs文件系统,也就是内存中 第二步,将session存储到不通的目录中 php本身支持session的多级散列 在php.ini中,将 ;session.sa

redis基本命令之一:字符串、散列、列表

1.Redis命令 1.1获得符合规则的键名列表 keys pattern   1.2判断一个键是否存在 exists key 1.3删除键 del key 1.4获得键值的数据类型 type key   2.redis字符串类型 2.1赋值与取值 set key value get key 2.2 递增数字 字符串类型可以存储任何形式的字符串,当存储的字符串是整数形式时,redis提供了一个使用的命令INCR,其作用是让当前键值递增,并返回递增后的值,用法为: incr num 当要操作的键不

Android数据加密之SHA安全散列算法_Android

前言: 对于SHA安全散列算法,以前没怎么使用过,仅仅是停留在听说过的阶段,今天在看图片缓存框架Glide源码时发现其缓存的Key采用的不是MD5加密算法,而是SHA-256加密算法,这才勾起了我的好奇心,所以趁着晚上没啥事,来学习一下. 其他几种加密方式:  •Android数据加密之Rsa加密  •Android数据加密之Aes加密  •Android数据加密之Des加密  •Android数据加密之MD5加密  •Android数据加密之Base64编码算法 SHA加密算法      SH

JS+CSS3实现超炫的散列画廊特效_javascript技巧

下面来介绍下我按照网上的视频讲解实现的照片墙效果图. 最终实现的效果包括如下:  •当点击某张图片时,该图片移到中间区域并放大显示.当图片被点击时正反面切换显示. •某张图片被点击时,所有的图片的位置被随机重排 •某个控制按钮被点击时,对应的图片显示到正中间,控制按钮进行相应的样式切换.当连续点击某个控制按钮时,图片伴随着按钮的点击进行正反面切换  对整个效果进行VCD分解,如下图:  按照计算机能理解的方式来分解案例.  •View视觉 : HTML + css 基本界面模板 •Control

Javascript实现Java的HashMap(链表散列)

前言 如果你研究过Java中HashMap的源码,你就会知道HashMap底层的存储结构.Java中的HashMap是以链表散列的形式存储的,也就是数组+链表:HashMap中有一个Entry数组,默认的数组长度是16.这个值必须是2的整数次幂,以保证在通过key的hash值来计算entry应该放置的数组下标时可以尽量做到平均分配.而Entry数组中的每一个非空Entry都是一个Entry链表的头结点.这样做的好处就是HashMap结合了数组在寻址(查找)上的优势和链表在放置和删除上的优势.当一