return new BloomFilter<T>(new LockFreeBitArray(numBits), numHashFunctions, funnel, strategy);
throw new IllegalArgumentException("Could not create BloomFilter of " + numBits + " bits", e);
从代码可以看出，需要4个参数，分别是
funnel 用来对参数做转化,方便生成hash值
expectedInsertions 预期插入的数据量大小，也就是上文公式中的n
fpp 误判率，也就是上文公式中的误判率p
strategy 生成hash值的策略，guava中也提供了默认策略，一般不需要你自己重新实现
从上面代码可知，BloomFilter创建过程中先检查参数的合法性，之后使用n和p来计算bitmap的大小m（optimalNumOfBits(expectedInsertions, fpp)），通过n和m计算hash函数的个数k（optimalNumOfHashFunctions(expectedInsertions, numBits)）,这俩方法的具体实现如下。
static int optimalNumOfHashFunctions(long n, long m) {
// (m / n) * log(2), but avoid truncation due to division!
return Math.max(1, (int) Math.round((double) m / n * Math.log(2)));
static long optimalNumOfBits(long n, double p) {
if (p == 0) {
p = Double.MIN_VALUE;
return (long) (-n * Math.log(p) / (Math.log(2) * Math.log(2)));
其实就是上文中列出的计算公式。
后面插入和查找的逻辑就比较简单了，这里不再赘述，有兴趣可以看下源码，我们这里通过BloomFilter提供的方法列表了解下它的功能就行。
从上图可以看出，BloomFilter除了提供创建和几个核心的功能外，还支持写入Stream或从Stream中重新生成BloomFilter，方便数据的共享和传输。
HBase、BigTable、Cassandra、PostgreSQ等著名开源项目都用BloomFilter来减少对磁盘的访问次数，提升性能。
Chrome浏览器用BloomFilter来判别恶意网站。
爬虫用BloomFilter来判断某个url是否爬取过。
比特币也用到了BloomFilter来加速钱包信息的同步。
和HashSet对比
我们一直在说BloomFilter有巨大的存储优势，做个优势到底有多明显，我们拿jdk自带的HashSet和guava中实现的BloomFilter做下对比，数据仅供参考。
测试平台 Mac
guava(28.1)BloomFilter，JDK11(64位) HashSet
使用om.carrotsearch.java-sizeof计算实际占用的内存空间
BloomFilter vs HashSet
分别往BloomFilter和HashSet中插入UUID，总计插入100w个UUID，BloomFilter误判率为默认值0.03。每插入5w个统计下各自的占用空间。结果如下，横轴是数据量大小，纵轴是存储空间，单位kb。
可以看到BloomFilter存储空间一直都没有变，这里和它的实现有关，事实上你在告诉它总共要插入多少条数据时BloomFilter就计算并申请好了内存空间，所以BloomFilter占用内存不会随插入数据的多少而变化。相反，HashSet在插入数据越来越多时，其占用的内存空间也会越来越多，最终在插入完100w条数据后，其内存占用为BloomFilter的100多倍。
在不同fpp下的存储表现
在不同的误判率下，插入100w个UUID，计算其内存空间占用。结果如下，横轴是误判率大小，纵轴是存储空间，单位kb。