高性能集合框架——fastUtils

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”); //這個迭代器將解析文件並返回其中的整數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章