Статьи

Коллекции Java Leaner с помощью FastUtil

В ответ на мой недавний пост « Обнаружение обработки коллекции примитивов Java в библиотеке GNU Trove» TheAlchemist указал на некоторые преимущества fastutil над trove : «Я очень предпочитаю fastutil ( http://fastutil.di.unimi.it/ ), потому что он все еще находится в активной разработке, имеет больше функций, поддерживает большие размеры (> 2 ^ 32) и имеет лучшую документацию ». Аттила- Михай Балаз поддержал это: «Я второй @ рекомендация TheAlchemist для fastutil! Это отличная библиотека ». В этом посте я рассматриваю fastutil с некоторых из тех же точек зрения, что и ранее.

Главная страница fastutil описывает fastutil как расширение платформы Java TM Collections Framework, которая предоставляет «карты, наборы, списки и очереди для конкретных типов с небольшим объемом памяти и быстрым доступом и вставкой» наряду с «большими (64-разрядными) массивами, наборы и списки, а также быстрые, практичные классы ввода / вывода для двоичных и текстовых файлов ». Лицензия для fastutilApache 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 .