fastutil通过提供特定类型的映射,集合,列表和优先级队列来扩展Java™集合框架,并且占用内存很少,并且可以快速访问和插入; 还提供大(64位)数组,集和列表,以及用于二进制和文本文件的快速,实用的I / O类。
性能
特定类型的Map和Set比标准的集合类快上2-10倍。但是以对象作为key的HashMap往往比jdk的HashMap慢,因为fastutil不会缓存hashCode。
fastutil的树状数据结构有红黑树和AVL。树小时,红黑树速度更快,avl在大的数据时效率更高。
fastutil极大的减少了对象的创建和收集。使用多态的方法和迭代器,减少包装类的创建。fastutils的Hash结构的map采用开放地址法,避免hash条目的创建和垃圾回收。
三个核心组成
1、扩展自JAVA集合框架的特定类型的类,如IntList,IntSet.
2、支持大集合的类
3、快速访问二进制文件和文本文件的类
特定类型集合类
通过大量特定类型的集合类,避免自动开箱/拆箱,提高性能和节省内存。
Fastutils集合类的命名规范
1、集合:数据类型+集合类型 如:IntArrayList,IntArraySet等;
2、映射:Key类型+2+value类型+Map类型 如Int2IntArrayMap;
1)、所有fastutil数据结构都根据固定的类型扩展,尝试使用错误类型的键或值都会产生一个ClassCastException。如Int类型的IntArrayList集合只能加入int类型的元素。fastutils中的集合数据类型有10种:8种基本数据类型+Object+Reference。
2)、要使用引用类型的集合,需要使用Object类型或者Reference类型的集合类,例如ObjectArrayList,ReferenceArrayList。
3)、fastutils的数据结构类都实现了对应jdk的标准接口(List,Set,Map等)。
使用例子
//===========IntList
//1、初始化
IntList list = new IntArrayList();
//2、利用数组快速初始化集合
IntList list = new IntArrayList(new int[]{1,2,3});
for(int i = 0; i < 1000; i++){
list.add(i);
}
//取值
int value = list.getInt(0);
System.out.println(value);// 0
//转成数组
int[] values = list.toIntArray();
System.out.println(values.length);// 1000
//遍历
IntListIterator i = list.iterator();
while(i.hasNext()){
System.out.println(i.nextInt());
}
//===========Int2BooleanMap
//1、初始化Map
Int2BooleanMap map = new Int2BooleanArrayMap();
map.put(1, true);
map.put(2, false);
//2、利用数组快速初始化Map 1-->true 2-->false
Int2BooleanMap map = new Int2BooleanArrayMap(new int[]{1,2},new boolean[]{true,false});
//取值
boolean value1 = map.get(1);
boolean value2 = map.get(2);
//设置默认值
map.defaultReturnValue(false);
boolean value3 =map.get(3);
System.out.println(value1);// true
System.out.println(value2);// false
System.out.println(value3);// false
//===========IntBigList 大数据集合的使用
IntBigList biglist = new IntBigArrayBigList();
biglist.add(0);
biglist.add(1);
biglist.add(2);
long size = biglist.size64();
//取值
for(long index = 0; index < size; index++) {
System.out.println(biglist.getInt(index));
}
//===========IntSortedSet
IntSortedSet s = new IntLinkedOpenHashSet( new int[] { 4, 3, 2, 1 } );
//获取第一个元素
System.out.println(s.firstInt()); // 4
//获取最后一个元素
System.out.println(s.lastInt()); // 1
//判断是否包含一个元素
System.out.println(s.contains(5)); // false
使用注意
1、fastutils集合中,引用类型的对比是使用“=”比较,而不是equal()。例如ReferenceArrayList中的contains方法,是通过使用”=”号判断是否包含一个类。Map的key如果用引用类型,get的时候也是通过地址值比对而不是实现的euqals方法 例:
class Bean(){
private int id;
public Bean(int id){
this.id=id;
}
public int hashCode(){
return Objects.hash(id);
}
public int getId(){
return id;
}
public boolean equals(Object o){
if(o ==null || getClass()!=o.getClass()) return false;
Bean bean =(Bean)o;
return id==bean.getId();
}
}
public void test(){
Reference2IntArrayMap map = new Reference2IntArrayMap();
Bean b1 = new Bean(1);
Bean b2 = new Bean(2);
map.put(b1,1);
map.put(b2,2);
b1.equals(new Bean(1)); // true
map.getInt(new Bean(1)); // 0 获取不到值,默认取0
map.getInt(b1); // 1
}
2、value是基本数据类型的Map都设置了默认的返回值,如果获取不存在的key的值时,返回的不是null,而是默认的返回值。如数值类型是 0,boolean类型是false,char是'\0'
Int2IntMap map = new Int2IntArrayMap(new int[]{1,2,3},new int[]{1,2,3});
map.get(1); // 1
map.get(4); // 0
3、链表结构的Map并没有完成实现jdk的SortedMap接口,在获取子Map或子Set都会报UnsupportedOperationException。
Int2IntLinkedOpenHashMap map = new Int2IntLinkedOpenHashMap(new int[]{1,2,3,4},new int[]{1,2,3,4});
map.tailMap(2); //throw UnsupportedOperationException
4、fastutil是不推荐使用包装类型。官方建议再开发工具中设置标记自动装箱/拆箱为警告,以防止无意的自动装箱/拆箱导致使用了错误的方法。
FastUtils对jdk集合接口和方法的增强
1、fastUtils的Map的values和keys都是fastUtils的数据类型。如Int2LongSortedMap的,keys是IntSortedSet,values 是LongCollection。
2、Hash或树结构的Map,且返回值是基础数据类型,有addTo方法来增加一个key的当前值。
Int2IntLinkedOpenHashMap map = new Int2IntLinkedOpenHashMap(new int[]{1,2,3,4},new int[]{1,2,3,4});
map.get(1); // 1
map.addTo(1,2); // 1+2, 返回原value
map.get(1); // 3
3、为哈希链表结构的Map提供了额外的方法来使它更容易作为缓存使用。
Int2IntLinkedOpenHashMap map = new Int2IntLinkedOpenHashMap(new int[]{1,2,3,4},new int[]{1,2,3,4});
map.putAndMoveToLast(1,3); //更新key=1的值,并把key=1的entry放到队尾
map.putAndMoveToFirst(1,3); //更新key=1的值,并把key=1的entry放到队头
map.getAndMoveToLast(1);//获取key=1的值,并把key=1的entry放在队尾
map.getAndMoveToFirst(1);//获取key=1的值,并把key=1的entry放在队头
4、可排序的数据结构返回的迭代器是双向的。
IntLinkedOpenHashSet sets = new IntLinkedOpenHashSet(new int[]{1,2,3,4});
IntListInterator iterator = sets.iterator();
//向后遍历
while(iterator.hasNext()){
System.out.println(iterator.nextInt());
}
//向前遍历
while(iterator.hasPrevious()){
System.out.println(iterator.perviousInt());
}
5、提供构造函数可以通过数组或迭代器快速初始化集合类
new ObjectOpenHashSet( new String[] { "foo", "bar" } )
new IntArrayList( iterator )
静态容器类
fastutil为各种集合类提供了大量的静态方法和单例,类似Collections.可以通过这些静态容器类可以轻松获取空集合,空类型特定集合,单元素的集合,任何特定类型集合的同步版本以及不可修改的集合和 迭代器。
IntList sigl=IntLists.singleton(1);
sigl.add(2) //不能做修改添加元素的操作,UnsupportedOperationException
//获取一个不可变的List
IntList unmodifiable =IntLists.unmodifiable(new IntArrayList(new int[]{1,2}));
//获取一个同步的List
IntList synchronizeList =IntLists.synchronize(new IntArrayList(new int[]{1,2}));
为数组提供了特定类型的静态容器类
//您可以使用lambda表达式指定的特定于类型的比较器对数组进行排序:
IntArrays.quickSort(a,(x,y) - > y - x); //按相反顺序排序
//如果您有多个核心,则可以并行执行:
IntArrays.parallelQuickSort(a,(x,y) - > y - x);
//返回增长长度的集合
int[] arr = new int[]{1,2,3,4,5,6,7,8,9,10}
int[] afterGrowArr=IntArrays.grow(arr,arr.length*2); //数组增长的长度必定是原数组一半的倍数。
afterGrowArr.length; // 20
一些映射在其入口集上提供了快速迭代器:允许这样的迭代器重用Map.Entry,从而大大减少了垃圾收集(例如,对于大型散列映射)。要轻松访问这些迭代器,我们可以使用辅助静态方法
Int2IntOpenHashMap m = new Int2IntOpenHashMap();
for(Int2IntMap.Entry e:Int2IntMaps.fastIterable(m)){
e.getIntKey();
e.etIntValue();
}
自定义Hash策略的Map
fastutil实现的Map使用的Hash策略也许不是你想要的,或者在Map中key的比较你更想要通过equals方法而不是‘=’,可以通过自定义Hash策略实现。注意fastutil不会缓存hashCode,所以hash算法不宜太复杂。
//Bean类是用上面代码的Bean
Object2IntOpenCustomHashMap o2I = new Object2IntOpenCustomHashMap(new Hash.Strategy(){
@Override
public int hashCode(Bean bean){
return bean.hashCode();
}
@Override
public boolean equals(Bean bean,Bean k1){
return bean.equals(k1);
}
});
o2I.put(new Bean(1),1);
o2I.getInt(new Bean(1)); //得到结果 1 ,这里对象不再用‘=’比较,而是用equals方法。
迭代器和比较器
fastutil提供了各种特定类型的迭代器和比较器。fastutil的迭代器接口比jdk的迭代器接口更加丰富。例如包含skip方法,用于跳过集合某个元素。
//使用迭代器
IntList list = new IntArrayList();
IntListIterator i = list.iterator();
while(i.hasNext()){
System.out.println(i.nextInt());
}
比较器使用
list.sort(new IntComparator(){
@Override
public int compare(int i,int i1){
return i-i1;
}
});
也可以使用lambda表达式
list.sort((x,y)->{
return x-y;
})
这些数据结构和10种类型组合成fastutils的集合类
接口 | 抽象实现 | 实现 |
---|---|---|
Iterable | ||
Collection | AbstractCollection | |
Set | AbstractSet | OpenHashSet, OpenCustomHashSet, ArraySet,OpenHashBigSet |
SortedSet | AbstractSortedSet | RBTreeSet, AVLTreeSet, LinkedOpenHashSet |
Function | AbstractFunction | |
Map | AbstractMap | OpenHashMap, OpenCustomHashMap, ArrayMap |
SortedMap | AbstractSortedMap | RBTreeMap, AVLTreeMap, LinkedOpenHashMap |
List , BigList† | AbstractList, AbstractBigList | ArrayList, BigArrayBigList, ArrayFrontCodedList |
PriorityQueue† | HeapPriorityQueue, ArrayPriorityQueue, ArrayFIFOQueue | |
IndirectPriorityQueue | HeapSemiIndirectPriorityQueue, HeapIndirectPriorityQueue, ArrayIndirectPriorityQueue | |
Stack | ArrayList | |
Iterator, BigListIterator | ||
Comparator | ||
BidirectionalIterator | ||
ListIterator | ||
Consumer | ||
Size64 |
以文本和 二进制形式存储和检索数据。只要您有一些数据结构,就可以很容易地以高效(缓冲)方式对其进行序列化,或者以文本形式转储它们的内容
Int2BooleanMap s = new Int2BooleanArrayMap(new int[]{1,2},new boolean[]{true,false});
BinIO.storeObject(s,“foo”); //此方法调用将s保存在名为“foo”的文件中
TextIO.storeInts(s.intIterator(),“foo.txt”); //此方法调用将以ASCII格式保存s的内容
i = TextIO.asIntIterator(“foo.txt”); //这个迭代器将解析文件并返回其中的整数