Статьи

Создание коллекции и неизменность с помощью Google Guava

Итак, я решил взглянуть на некоторые шаблоны создания коллекций, которые предлагает Guava, а также на некоторые типы коллекций, которые она предлагает.

Если вы не видели мои предыдущие сообщения, вы можете начать здесь:

Гуава часть 1 — MultiMaps

Гуава часть 2 — BiMaps Гуава

часть 3 — MultiSet

методы создания

Все реализации коллекций Guava содержат один или несколько статических методов create, они делают то, что вы ожидаете, и обычно предлагают несколько более краткий способ создания экземпляров классов коллекции.

Вот два разных способа создания ArrayListMultimap

Multimap<String,String> multimap1 = new ArrayListMultimap<String,String>();
Multimap<String,String> multimap2 = ArrayListMultimap.create();

Итак, в нем не так уж много — 12 символов в этом примере — но, как я вижу, вы удаляете некоторую избыточность, нам действительно нужно дважды воспроизвести информацию о типе Generic?

Это хорошо, жаль, что Sun не думала добавлять методы create к своим типам Collection, когда создавала Java 5!

Опять же, Гуава поможет вам в этом и предоставит несколько полезных классов для работы со стандартными типами коллекций. com.google.common.collect.Lists , com.google.common.collect.Sets и com.google.common.collect.Maps

Каждый из них предоставляет несколько методов формата new CollectionType (), вот несколько примеров

List<String> myList1 = new ArrayList<String>(); //old way
List<String> myList2 = Lists.newArrayList();    //guava way
 
Set<String> mySet1 = new HashSet<String>(); //old way
Set<String> mySet2 = Sets.newHashSet();     //guava way

Поскольку «новые» методы являются статическими, вы можете вырезать еще больше символов, используя статический импорт, т.е.

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Sets.newHashSet;
 
//elsewhere in code
List<String> myList2 = newArrayList();
Set<String> mySet2 = newHashSet();

Если вы нажимаете на клавишу, вы не особо экономите на методах гуавы, поэтому я думаю, что это вопрос вкуса, как и все остальное. Лично я думаю, что способ Guava читается намного лучше, хотя я думаю, что я бы обошелся без статического импорта.

Пока все хорошо, но вряд ли земля разрушит, что дальше?

Неизменные коллекции

По сути, это объекты коллекции, которые нельзя изменить после их создания, и они полезны по разным причинам. Guava предоставляет неизменные реализации для большинства обычных интерфейсов Collection: ImmutableList , ImmutableSet и ImmutableMap , а также неизменные реализации некоторых интерфейсов коллекции Guava ( ImmutableMultimap и т. Д.)

Мое основное использование для них — создание статических констант. Например, допустим, вам нужно жестко закодировать набор строк для какой-то цели. Одним из способов сделать это может быть, например.

private static final Set<String> farmAnimals =
            new HashSet<String>(Arrays.asList("Cow","Pig","Sheep"));

Не выглядит великолепно, делает это, и это страдает от одной серьезной проблемы. Любой код, который может получить доступ к этому набору, также может изменить его, что может привести к всевозможным неожиданным проблемам.

Не могли бы мы просто использовать Collection.unmodifiableSet (Set s) для решения этой проблемы?

Ну, в этом конкретном примере, я думаю, мы могли бы написать …

private static final Set<String> farmAnimals =
     Collections.unmodifiableSet(
            new HashSet<String>(Arrays.asList("Cow","Pig","Sheep")));

… но это начинает казаться немного громоздким, и немодифицируемые методы имеют еще одну проблему. Они только возвращают неизменяемый вид коллекции, если у вас есть ссылка на оригинальную коллекцию, вы все равно можете ее изменить!

Хотя это может и не быть проблемой в последнем примере, я все же думаю, что гораздо лучший способ сделать это — использовать ImmutableSet

private static final Set<String> farmAnimals =
                   ImmutableSet.of("Cow","Pig","Sheep");

Это намного лучше, не правда ли! И есть несколько других способов их создания, вот несколько примеров:

// use copyOf()...
public void doStuffWithList(List<Object> unsafeList) {
   List<Object> safeList = ImmutableList.copyOf(unsafeList);
}
// use a builder...
public Map<String,Integer> makeImmutableMap() {
    ImmutableMap.Builder<String,Integer> mapBuilder =
                     new ImmutableMap.Builder<String,Integer>();
    Entry<String,Integer> entry = null;
    while((entry = getEntry()) != null) {
        mapBuilder.put(entry.getKey(), entry.getValue());
    }
    return builder.build();
}

Итак, есть ли другие преимущества использования неизменных коллекций?

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

Их также немного эффективнее использовать после их создания. Если коллекция знает заранее, что ей нужно хранить, и никаких изменений не произойдет, вы можете сэкономить время и пространство. Например, большинство реализаций ArrayLists или HashMaps оставляют некоторое неиспользуемое пространство для новых объектов, поэтому им не нужно постоянно изменять свой размер. Если вы знаете, что новых объектов никогда не будет, в этом нет необходимости.

Наконец, вы также можете использовать их в качестве ключей хеша. Если содержимое коллекции не может измениться, то и хеш-код не изменится!

Есть ли недостатки?

Конечно, есть один большой недостаток неизменяемых объектов, который довольно очевиден. Вы не можете изменить их! Если вам нужно изменить коллекцию, вам сначала нужно взять ее копию. В определенных ситуациях, т. Е. Там, где параллелизм является проблемой, вы, возможно, захотите использовать этот подход. Однако это будет непрактично, если коллекции содержат много объектов, и вам, вероятно, понадобится старая добрая изменчивая коллекция (дополненная кодом синхронизации, если требуется).

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