Статьи

Функциональные коллекции Java

В наши дни много функциональной ажиотажа, поэтому я бы дал краткий обзор того, что там есть, по крайней мере, когда речь идет о коллекциях в Java. Лично мне нравится стандарт
API коллекций, но в некоторых случаях это может быть неудобно и добавлять дополнительную многословность. Это не должно быть проблемой в последней версии Java 8+. Там мы, вероятно, беспокоимся о том, чтобы не создавать ад-колбэк, но эй, для большинства вещей нет серебряной пули, почему она должна быть для программирования?

Путь гуавы

Проект Guava — одна из основных библиотек Google, в которой есть множество различных основных языковых аспектов и проблем. Существуют утилиты и расширения для повседневного использования, такие как: коллекции, примитивы, кэширование, общие аннотации, обработка строк, ввод-вывод, математика, отражения и многие другие. Мы только взглянем на вкусности Коллекций, поэтому давайте посмотрим на некоторые из них:

1
2
3
4
5
6
7
8
// list
    ImmutableList<String> of =
        ImmutableList.of("a", "b", "c", "d");
    // Same one for map
    ImmutableMap<String, String> map =
         ImmutableMap.of("key1", "value1", "key2", "value2");
    //list of ints
    List<Integer> theList = Ints.asList(1, 2, 3, 4, 522, 5, 6);

Коллекции Guava совместимы с коллекциями JDK, поскольку они в основном расширяют или реализуют стандартные классы. Есть несколько классных утилит, которые являются частью API и имеют схожие названия с именами из java.util.Collections . По сути, любой программист, который знает коллекции JDK, должен легко переносить их в Guava. Те, что для списка , называются списками , одна для набора — наборы, для картыкарты и так далее для остальных. Например:

01
02
03
04
05
06
07
08
09
10
11
//create new List
List<someLongName> list = Lists.newArrayList();
//create new  LinkedHashMap
Map<someKeyType, SomeValueType> map = Maps.newLinkedHashMap();
 
//initalize Array List on the spot
List<String> someList = Lists.newArrayList("one", "two", "three");
 
//set inital size for readability as well as performance
List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);

Методы, соответствующие определенному интерфейсу, сгруппированы очень интуитивно. Есть также несколько очень хороших способов построения кеша с различными функциями:

01
02
03
04
05
06
07
08
09
10
11
12
Cache<Integer, Customer> cache = CacheBuilder.newBuilder()
        .weakKeys()
        .maximumSize(10000)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .build(new CacheLoader<Integer, Customer>() {
 
          @Override
          public Customer load(Integer key) throws Exception {
 
            return retreveCustomerForKey(key);
          }
        });

Так как Guava доступен в большинстве репозиториев Maven, очень легко добавить его в вашу сборку.

LAMBDAJ

Идея проекта заключается в том, чтобы манипулировать коллекциями функционально и статически. Это достигается таким образом, чтобы избежать повторений простых задач, которые мы обычно делаем с коллекциями. Повторение заставляет программистов выполнять копирование / вставку, а создание заставляет их создавать ошибки, делая это. Доступ к коллекциям без явного зацикливания предоставляет способ фильтрации, сортировки, извлечения, группировки, преобразования, вызова метода для каждого элемента или суммирования элементов или полей этих элементов в коллекциях. В дополнение ко всем этим функциям lambdaj также является своего рода DSL, так как он добавляет очень интересные «сахарные» функции в синтаксис, делая его более читабельным в псевдоанглийском. Это делается статическими методами, поэтому для их использования мы включаем их напрямую:

1
import static ch.lambdaj.Lambda.*;

Что касается проверки и сопоставления, то лямбдаж сильно зависит от совпадений Hamcrest. Так, например, чтобы создать проверку для нечетных целых чисел, а затем отфильтровать список с этой проверкой:

1
2
3
4
5
6
Matcher<Integer> odd = new Predicate<Integer>() {
        public boolean apply(Integer item) {
                return item % 2 == 1;
        }
};
List<Integer> oddNumbers = filter(odd, asList(1, 2, 3, 4, 5));

и, как ожидается, список вернет список [1,3,5]. Lambdaj делает шаг вперед с помощью DSL, например:

1
2
3
4
5
List<Beneficiary> beneficiaries = with(transactions)
    .retain(having(on(Transaction.class)
              .getQunatity(), lessThan(100)))
    .extract(on(Transaction.class).getBeneficiary())
    .sort(on(Beneficiary.class).getName());

Расходы на исполнение

Хотя лучший способ сделать ваше приложение быстрым — иметь максимально чистый код, наступает момент, когда вы должны оптимизировать. Для этого есть некоторая информация, предоставленная создателями об использовании памяти и времени. У Lambdaj есть вики-страница о производительности с примерами кода. Есть также некоторые тесты, выполненные другими программистами, где они сравнивают, например, lambdaj с JDK8. Есть также некоторые измерения использования памяти Guava. Что касается производительности Guava, то большая часть его функциональных возможностей — стандартные компоновщики классов JDK и утилиты, поэтому накладные расходы минимальны. В конце концов, вам решать, насколько каждая из этих библиотек окажет влияние на ваш проект и будет ли это позитивно. Я за идею, что почти каждый проект должен иметь Guava на своем пути к классам.

Сводка по ссылкам

Ссылка: Функциональные коллекции Java от нашего партнера по JCG Мите Митрески в блоге Java Advent Calendar .