В ответ на мой недавний пост « Обнаружение обработки коллекции примитивов Java в библиотеке GNU Trove» TheAlchemist указал на некоторые преимущества fastutil над trove : «Я очень предпочитаю fastutil ( http://fastutil.di.unimi.it/ ), потому что он все еще находится в активной разработке, имеет больше функций, поддерживает большие размеры (> 2 ^ 32) и имеет лучшую документацию ». Аттила- Михай Балаз поддержал это: «Я второй @ рекомендация TheAlchemist для fastutil! Это отличная библиотека ». В этом посте я рассматриваю fastutil с некоторых из тех же точек зрения, что и ранее.
Главная страница fastutil описывает fastutil как расширение платформы Java TM Collections Framework, которая предоставляет «карты, наборы, списки и очереди для конкретных типов с небольшим объемом памяти и быстрым доступом и вставкой» наряду с «большими (64-разрядными) массивами, наборы и списки, а также быстрые, практичные классы ввода / вывода для двоичных и текстовых файлов ». Лицензия для fastutil — Apache License, версия 2, а для текущей версии fastutil требуется Java 7 или более поздняя версия. В настоящее время (на момент написания этой статьи) доступны для загрузки «не поддерживаемые» версии fastutil, а также для Java 6 и Java 5 .
Добавление элементов в коллекцию FastUtil выполняется с помощью тех же вызовов API, которые используются со стандартными коллекциями Java, как показано в следующем листинге кода, в котором сравниваются вставка элементов в JDK ArrayList со вставкой элементов в FastUtil DoubleArrayList .
Вставка двойников с JDK и Вставка двойников с FastUtil DoubleArrayList
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/** * Demonstrate standard JDK {@code ArrayList<Double>} * with some JDK 8 functionality. */public void demonstrateJdkArrayListForDoubles(){ final ArrayList<Double> doubles = new ArrayList<>(); doubles.add(15.5); doubles.add(24.4); doubles.add(36.3); doubles.add(67.6); doubles.add(10.0); out.println("JDK ArrayList<Double>:"); out.println("\tDoubles List: " + doubles);}/** * Demonstrate use of DoubleArrayList and show how * similar using it is to using {@code ArrayList<Double>}. */public void demonstrateFastUtilArrayListForDoubles(){ // Demonstrate adding elements to DoubleArrayList is // exactly like adding elements to ArrayList<Double>. final DoubleArrayList doubles = new DoubleArrayList(); doubles.add(15.5); doubles.add(24.4); doubles.add(36.3); doubles.add(67.6); doubles.add(10.0); out.println("FastUtil DoubleArrayList:"); // DoubleArrayList overrides toString() out.println("\tDoubles List: " + doubles);} |
Когда два вышеуказанных метода выполняются, список значений типа double, записываемых в стандартный вывод, выглядит одинаково даже с одинаковыми квадратными скобками, окружающими значения типа double, разделенные запятыми.
Коллекции FastUtil имеют тенденцию реализовывать соответствующие интерфейсы коллекций JDK. Например, только что продемонстрированный класс DoubleArrayList реализует несколько интерфейсов, включая Collection <Double> и List <Double>. Оказывается, что DoubleArrayList также реализует it.unimi.dsi.fastutil.doubles.DoubleStack и it.unimi.dsi.fastutil.Stack <Double> . Возможность использовать этот класс в качестве стека продемонстрирована в следующем листинге кода.
Использование DoubleArrayList от FastUtil в качестве стека
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
/** * Demonstrate FastUtil's Double Stack. * * FastUtil's DoubleStack allows access to its * contents via push, pop, and peek. It is declared * as a DoubleArrayList type here so that the size() * method is available without casting. */public void demonstrateFastUtilDoubleStack(){ final DoubleArrayList stack = new DoubleArrayList(); stack.push(15.5); stack.push(17.3); stack.push(16.6); stack.push(2.2); out.println("FastUtil Stack of Doubles"); out.println("\tPeek: " + stack.peek(0) + "; After Size: " + stack.size()); out.println("\tPop: " + stack.pop() + "; After Size: " + stack.size()); out.println("\tPeek: " + stack.peek(0) + "; After Size: " + stack.size());} |
Как я уже говорил в блоге о Trove , Trove предоставляет класс gnu.trove.TCollections, который является аналогом (подмножеством) java.util.Collections . FastUtil предоставляет аналогичную функциональность, но этот подход предоставления статических методов для работы с коллекциями FastUtil разделен на классы, специфичные для типа и структуры, со статическими методами, а не в одном классе со статическими методами. В следующем листинге кода показано использование одного из этих классов, специфичных для типа и структуры, со статическими методами, IntSets , в сочетании с FastUtil IntLinkedOpenHashSet. Как следует из названия, класс IntSets предоставляет «статические методы и объекты, которые делают полезные вещи с [int] -специфичными наборами».
Использование IntSets с IntLinkedOpenHashSet
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/** * Demonstrate one of FastUtil's "equivalent"s of the * java.util.Collections class. FastUtil separates its * grouping of static methods into classes that are * specific to the data type of the collection and to * the data structure type of the collection. */public void demonstrateFastUtilCollectionsClass(){ final IntLinkedOpenHashSet integers = new IntLinkedOpenHashSet(); integers.add(5); integers.add(7); integers.add(3); integers.add(1); final IntSet unmodifiableIntegers = IntSets.unmodifiable(integers); out.println("Unmodifiable Integers:"); out.println("\tClass: " + unmodifiableIntegers.getClass().getCanonicalName()); try { unmodifiableIntegers.add(15); } catch (Exception ex) { out.println("\tException caught: " + ex); }} |
FastUtil поддерживает этот стандартный подход итерации Java с использованием явного итератора и использования цикла Java SE 5, введенного для каждого . Коллекции FastUtil даже поддерживают стиль JDK 8, используя .forEach (при условии, что код собран и выполняется на JDK 8), потому что коллекции FastUtil реализуют java.lang.Iterable . Это продемонстрировано в следующем листинге кода.
Итерация коллекций FastUtil в стандартном стиле Java
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
/** * Demonstrate "traditional" Java iteration of a * FastUtil collection. */public void demonstrateIterationWithIterator(){ final LongOpenHashSet longs = new LongOpenHashSet(); longs.add(15); longs.add(6); longs.add(12); longs.add(13); longs.add(2); final LongIterator longIterator = longs.iterator(); while (longIterator.hasNext()) { final long longValue = longIterator.next(); out.print(longValue + " "); }}/** * Demonstrate iteration of a FastUtil collection * using Java's enhanced for-each approach. */public void demonstrateIterationWithForEach(){ final LongLinkedOpenHashSet longs = new LongLinkedOpenHashSet(); longs.add(15); longs.add(6); longs.add(12); longs.add(13); longs.add(2); for (final long longValue : longs) { out.println(longValue + " "); }}/** * Demonstrate iteration of a FastUtil collection * using JDK 8 .forEach approach. */public void demonstrateIterationWithJdk8ForEach(){ final LongLinkedOpenHashSet longs = new LongLinkedOpenHashSet(); longs.add(15); longs.add(6); longs.add(12); longs.add(13); longs.add(2); longs.forEach(longValue -> out.print(longValue + " "));} |
Дополнительные замечания, связанные с FastUtil
- Поскольку коллекции FastUtil реализуют стандартные интерфейсы коллекций JDK 8, API легко подобрать и использовать со знакомыми идиомами Java.
- Коллекции FastUtil обычно предоставляют конструктор, который принимает массив базового типа данных, переопределенный метод toArray () и метод, специфичный для типа, например toDoubleArray () [для коллекций с двойной ориентацией], чтобы предоставлять свои элементы данных в виде массива примитивы.
- Коллекции FastUtil обычно предоставляют явно переопределенные реализации
toString()которые позволяют легко записывать отдельные элементы данных, аналогично коллекциям JDK и по-другому, чем массивы Java (для которых требуются методы Arrays.toString () ). - Java-пакеты FastUtil организованы в основном по типу примитивов с конкретными реализациями различных типов структур данных для этого типа примитивов в одном и том же пакете. Например, пакеты называются как it.unimi.dsi.fastutil.doubles , it.unimi.dsi.fastutil.ints и так далее.
- Поскольку каждая коллекция FastUtil относится к определенному примитивному типу данных, каждая коллекция не требует универсального параметра и не имеет никаких проблем, связанных с универсальными (например, стирание). Я не видел, чтобы FastUtil использовал преимущества коллекций, специфичных для типа, для методов, специфичных для типа, как Trove, возможно потому, что FastUtil более тесно реализует соответствующие интерфейсы Java-коллекций.
- Javadoc API-документация FastUtil — это, пожалуй, лучшее место, с которого можно начать изучать использование FastUtil. Классы, интерфейсы, перечисления и пакеты, как правило, довольно хорошо документированы в документации API FastUtil на основе Javadoc.
Вывод
Как и Trove , FastUtil — это библиотека, которая потенциально может использоваться для более эффективной (с точки зрения памяти и производительности) работы с коллекциями Java. Хотя Trove, кажется, раньше был самым популярным из множества доступных вариантов , FastUtil, пожалуй, является самым популярным в настоящее время по причинам, указанным TheAlchemist : «Все еще в активной разработке, имеет больше функций, поддерживает большие размеры (> 2 ^ 32 ) и имеет лучшую документацию ». Подобные библиотеки, кроме Trove и FastUtil, включают высокопроизводительные коллекции примитивов для Java ( HPPC ), Koloboke , коллекции Goldman Sachs , Mahout и Javolution .
| Ссылка: | Познакомьтесь с коллекциями Java с FastUtil от нашего партнера JCG Дастина Маркса в блоге Inspired by Actual Events . |