高性能集合框架——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”); //这个迭代器将解析文件并返回其中的整数

猜你喜欢

转载自blog.csdn.net/qq_26680031/article/details/81200055