Guia do FastUtil
1. Introdução
Neste tutorial, vamos olhar para a bibliotecaFastUtil .
Primeiro, vamos codificar alguns exemplos de seustype-specific collections.
Então, vamos analisar operformance that gives FastUtil its name.
Finalmente, vamos dar uma olhada emFastUtil‘s BigArray utilities.
2. Recursos
A biblioteca JavaFastUtil busca estender o Java Collections Framework. Ele fornece aotype-specific maps, sets, lists and queues uma pegada de memória menor e acesso e inserção rápidos. FastUtil also fornece um conjunto deutilities for working with and manipulating large (64-bit) arrays, sets and lists.
A biblioteca também inclui ummultitude of practical Input/Output classes para arquivos binários e de texto.
Seu lançamento mais recente,FastUtil 8,, também lançou um host detype-specific functions, estendendo oFunctional Interfaces. do JDK
2.1. Rapidez
In many cases, the FastUtil implementations are the fastest available. Os autores forneceram até mesmo seus própriosbenchmark report em profundidade, comparando-os com bibliotecas semelhantes que incluemHPPC andTrove.
Neste tutorial, vamos definir nossos próprios benchmarks usandoJava Microbench Harness (JMH).
3. Dependência de tamanho completo
Além da dependência usual deJUnit, estaremos usandoFastUtilseJMHdependencies neste tutorial.
Vamos precisar das seguintes dependências em nossopom.xml file:
it.unimi.dsi
fastutil
8.2.2
org.openjdk.jmh
jmh-core
1.19
test
org.openjdk.jmh
jmh-generator-annprocess
1.19
test
Ou para usuários Gradle:
testCompile group: 'org.openjdk.jmh', name: 'jmh-core', version: '1.19'
testCompile group: 'org.openjdk.jmh', name: 'jmh-generator-annprocess', version: '1.19'
compile group: 'it.unimi.dsi', name: 'fastutil', version: '8.2.2'
3.1. Arquivo Jar personalizado
Devido à falta de genéricos,FastUtils gera um grande número de classes específicas do tipo. E, infelizmente, isso leva a umhuge jar file.
No entanto, felizmente para nós,FastUtils includes a find-deps.sh script which allows generation of smaller, more focused jars compreende apenas as classes que queremos usar em nosso aplicativo.
4. Coleções específicas de tipo
Antes de começar, vamos dar uma olhada rápida emsimple process of instantiating a type-specific collection. Vamos escolher umHashMap que armazena chaves e valores usandodoubles.
Para este propósito,FastUtils oferece umaDouble2DoubleMap interface e umaDouble2DoubleOpenHashMap implificação:
Double2DoubleMap d2dMap = new Double2DoubleOpenHashMap();
Agora que instanciamos nossa classe, podemos simplesmente preencher os dados como faríamos com qualquerMap da API de coleções Java:
d2dMap.put(2.0, 5.5);
d2dMap.put(3.0, 6.6);
Por fim, podemos verificar se os dados foram adicionados corretamente:
assertEquals(5.5, d2dMap.get(2.0));
4.1. atuação
FastUtils focuses on its performant implementations. In this section, we’ll make use of the JMH to verify that fact. Vamos comparar a implementação deHashSet<Integer> das coleções Java contraFastUtil’s IntOpenHashSet.
Primeiro, vamos ver como implementar oIntOpenHashSet:
@Param({"100", "1000", "10000", "100000"})
public int setSize;
@Benchmark
public IntSet givenFastUtilsIntSetWithInitialSizeSet_whenPopulated_checkTimeTaken() {
IntSet intSet = new IntOpenHashSet(setSize);
for(int i = 0; i < setSize; i++) {
intSet.add(i);
}
return intSet;
}
Acima, nós simplesmente declaramos a implementaçãoIntOpenHashSet da face sinterizadaIntSet . Também declaramos o tamanho inicialsetSize com a anotação@Param .
Simplificando, esses números são inseridos no JMH para produzir uma série de testes de benchmark com diferentes tamanhos de conjunto.
A seguir,let’s do the same thing using the Java Collections implementation:
@Benchmark
public Set givenCollectionsHashSetWithInitialSizeSet_whenPopulated_checkTimeTaken() {
Set intSet = new HashSet<>(setSize);
for(int i = 0; i < setSize; i++) {
intSet.add(i);
}
return intSet;
}
Finalmente, vamos executar o benchmark e comparar as duas implementações:
Benchmark (setSize) Mode Cnt Score Units
givenCollectionsHashSetWithInitialSizeSet... 100 avgt 2 1.460 us/op
givenCollectionsHashSetWithInitialSizeSet... 1000 avgt 2 12.740 us/op
givenCollectionsHashSetWithInitialSizeSet... 10000 avgt 2 109.803 us/op
givenCollectionsHashSetWithInitialSizeSet... 100000 avgt 2 1870.696 us/op
givenFastUtilsIntSetWithInitialSizeSet... 100 avgt 2 0.369 us/op
givenFastUtilsIntSetWithInitialSizeSet... 1000 avgt 2 2.351 us/op
givenFastUtilsIntSetWithInitialSizeSet... 10000 avgt 2 37.789 us/op
givenFastUtilsIntSetWithInitialSizeSet... 100000 avgt 2 896.467 us/op
Esses resultados tornam claro o FastUtils implementation is much more performant than the Java Collections alternative.
5. Grandes coleções
Outro importantefeature of FastUtils is the ability to use 64-bit arrays. Arrays em Java, por padrão, são limitados a 32 bits.
Para começar, vamos dar uma olhada na classeBigArrays para os tiposInteger. IntBigArrays provides static methods for working with 2-dimensional Integer arrays. Usando esses métodos fornecidos, podemos essencialmente agrupar nosso array em um array unidimensional mais amigável.
Vamos dar uma olhada em como isso funciona.
Primeiro, vamos começar inicializando uma matriz unidimensional e convertendo-a em uma matriz bidimensional usando o métodoIntBigArray’s wrap :
int[] oneDArray = new int[] { 2, 1, 5, 2, 1, 7 };
int[][] twoDArray = IntBigArrays.wrap(oneDArray.clone());
Devemosmake sure to use the clone method to ensure a deep copy of the array.
Agora, como faríamos comList ou aMap, podemos obter acesso aos elementos usando o métodoget :
int firstIndex = IntBigArrays.get(twoDArray, 0);
int lastIndex = IntBigArrays.get(twoDArray, IntBigArrays.length(twoDArray)-1);
Finalmente, vamos adicionar algumas verificações para garantir que nossoIntBigArray retorne os valores corretos:
assertEquals(2, firstIndex);
assertEquals(7, lastIndex);
6. Conclusão
Neste artigo, pegamos umdive into FastUtils core features.
Vimos alguns dostype-specific collections that FastUtil offers, before playing around with some BigCollections.
Como sempre, o código pode ser encontrado emGitHub