FastUtils簡介
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<Bean> map = new Reference2IntArrayMap<bean>();
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<Bean> o2I = new Object2IntOpenCustomHashMap<Bean>(new Hash.Strategy<Bean>(){
@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;
})
fastutils數據結構
這些數據結構和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 |
IO
以文本和 二進制形式存儲和檢索數據。只要您有一些數據結構,就可以很容易地以高效(緩衝)方式對其進行序列化,或者以文本形式轉儲它們的內容
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”); //這個迭代器將解析文件並返回其中的整數