Статьи

Google Guava MultiMaps

Гуавы?

Это первая из серии публикаций, в которых я попытаюсь объяснить и изучить потрясающую библиотеку Java на языке гуавы от Google.

Я впервые наткнулся на Гуаву, когда искал универсальные версии коллекций Apache Commons — мне был нужен Bimap и мне Bimap свой код с помощью забросов — однако то, что я обнаружил, было намного лучше.

Он содержит не только различные реализации более сложных (но полезных) типов коллекций — Multimaps , Multisets , Bimaps — о которых я расскажу подробно, но также и средства поддержки более функционального стиля программирования с неизменяемыми коллекциями, а также функции и предиката объекты. Это полностью изменило то, как я пишу Java, и в то же время заставило меня все больше расстраиваться из-за неуклюжего синтаксиса Java, что я собираюсь исследовать в следующих статьях.

Во всяком случае, достаточно с введением и с хорошим материалом. Первое, на что я хотел бы взглянуть, это Multimap, которая, вероятно, является единственной функцией Guava, которую я использовал чаще всего.

Mutlimaps

Итак, как часто вам нужна структура данных, как показано ниже?

1
2
Map<String,List<MyClass>> myClassListMap test2
                              = new HashMap<String,List<MyClass>>()

Если вы похожи на меня, довольно часто. И разве вы не пишете один и тот же шаблонный код снова и снова?

Чтобы поместить пару ключ / значение в эту карту, необходимо сначала проверить, существует ли список для вашего ключа, и не создает ли он его. Вы закончите тем, что написали что-то вроде следующего:

1
2
3
4
5
6
7
8
void putMyObject(String key, Object value) {
    List<Object> myClassList = myClassListMap.get(key);
    if(myClassList == null) {
        myClassList = new ArrayList<object>();
        myClassListMap.put(key,myClassList);
    }
    myClassList.add(value);
}

Немного боли, а что, если вам нужны методы для проверки существования значения, или удаления значения, или даже итерации по всей структуре данных. Это может быть довольно много кода.

Никогда не бойся Гуава здесь!

Как и стандартные коллекции Java, Guava определяет несколько интерфейсов и соответствующих реализаций. Обычно вы хотите закодировать интерфейс и беспокоиться о реализации только при его создании. В этом случае нас интересуют мультикарты.

Таким образом, используя мультикарту, мы могли бы заменить объявление структуры данных следующим:

1
Multimap<String,Object> myMultimap = ArrayListMultimap.create();

Здесь есть несколько вещей, на которые стоит обратить внимание. Объявление универсального типа должно выглядеть очень знакомым, именно так вы бы объявили карту нормалей.

Возможно, вы ожидали увидеть new ArrayListMultimap<String,Object>() в правой части равенства. Что ж, все реализации коллекций Guava предлагают метод create , который обычно более лаконичен и имеет то преимущество, что вам не нужно дублировать информацию общего типа.

Guava фактически добавляет аналогичные функциональные возможности к стандартным коллекциям Java. Например, если вы изучите com.google.common.collect.Lists , вы увидите статические newArrayList() и newLinkedList() , так что вы можете воспользоваться этой краткостью даже со стандартными коллекциями 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
public class MutliMapTest {
    public static void main(String... args) {
  Multimap<String, String> myMultimap = ArrayListMultimap.create();
 
  // Adding some key/value
  myMultimap.put('Fruits', 'Bannana');
  myMultimap.put('Fruits', 'Apple');
  myMultimap.put('Fruits', 'Pear');
  myMultimap.put('Vegetables', 'Carrot');
 
  // Getting the size
  int size = myMultimap.size();
  System.out.println(size);  // 4
 
  // Getting values
  Collection<string> fruits = myMultimap.get('Fruits');
  System.out.println(fruits); // [Bannana, Apple, Pear]
 
  Collection<string> vegetables = myMultimap.get('Vegetables');
  System.out.println(vegetables); // [Carrot]
 
  // Iterating over entire Mutlimap
  for(String value : myMultimap.values()) {
   System.out.println(value);
  }
 
  // Removing a single value
  myMultimap.remove('Fruits','Pear');
  System.out.println(myMultimap.get('Fruits')); // [Bannana, Pear]
 
  // Remove all values for a key
  myMultimap.removeAll('Fruits');
  System.out.println(myMultimap.get('Fruits')); // [] (Empty Collection!)
 }
}

Вам может быть интересно узнать, почему метод get возвращает Collection а не List , что было бы гораздо более полезным. Это действительно так. Проблема в том, что существует несколько различных реализаций, некоторые из них используют Lists- ArrayListMultimap , LinkedListMultimap и т. Д., А некоторые используют наборы — HashMultimap , TreeMultimap и другие.

Чтобы справиться с этим — если вам нужно работать непосредственно со списками или наборами на карте, — определено несколько подынтерфейсов. ListMultimap , SetMultimap и SortedSetMultimap . Все они делают то, что вы ожидаете, и их методы, которые возвращают коллекции, возвращают один из подходящих типов.

т.е.

1
2
3
ListMutlimap<String,String> myMutlimap = ArrayListMultimap.create();
 
List<string> myValues = myMutlimap.get('myKey');  // Returns a List, not a Collection.

Это в основном все, что есть для них. Я рекомендую взглянуть на API: http://docs.guava-libraries.googlecode.com/git-history/release09/javadoc/com/google/common/collect/Multimap.html , где вы можете найти различные реализации, вы должен быть в состоянии найти тот, который соответствует вашим потребностям.


Ссылка: Multimaps — Google Guava от нашего партнера JCG Тома Джеффериса в блоге Tom’s Programming Blog .