За последний год я прочитал несколько блогов, статей и твитов о предстоящей функции в Java 9. Некоторые из статей были озаглавлены Неизменяемые коллекции в Java 9. В интерфейсах коллекций Java (List, Set, Map) появятся новые фабричные методы, которые будут создавать компактные, неизменяемые экземпляры коллекций. Эта функция описана в JEP 269 - http://openjdk.java.net/jeps/269. Эта функция будет долгожданным дополнением для многих разработчиков Java, особенно в таких местах, как модульные тесты, где создание небольших коллекций может быть частым и потенциально обременительным занятием.
Но… мы не получаем неизменяемые по контракту коллекции в Java 9, и JEP 269 не претендует на их предоставление. Если бы мы получали неизменяемые по контракту коллекции в Java 9, я бы ожидал увидеть новые интерфейсы с именами ImmutableCollection
, ImmutableSet
, ImmutableList
и ImmutableMap
. Эти интерфейсы могут иметь фабричные методы «of» для создания неизменяемых экземпляров коллекции, безопасных во время компиляции. ImmutableCollection
интерфейсы не должны иметь таких методов, как _6 _ / _ 7_, _8 _ / _ 9_, потому что эти методы небезопасны и могут вызывать только UnsupportedOperationException
.
Если вам нужны неизменяемые по контракту коллекции для Java, сегодня доступно несколько библиотек с открытым исходным кодом, которые их предоставляют. Eclipse Collections предоставляет как изменяемые, так и неизменяемые коллекции, а также имеет фабрики коллекций для них обоих. В части 1 этого блога я сравню изменяемые фабричные методы, доступные в коллекциях Eclipse, с новыми фабричными методами, которые будут добавлены в Java 9. Во второй части я исследую фабрики, доступные для неизменяемых коллекций.
Статические фабричные методы всегда были во всех реализациях изменяемых контейнеров в Eclipse Collections. Эти методы все еще доступны, поэтому вы можете написать следующее для создания изменяемых списков, наборов и карт с использованием коллекций Eclipse.
MutableList<String> list = FastList.newListWith("1", "2", "3"); MutableSet<String> set = UnifiedSet.newSetWith("1", "2", "3"); MutableMap<Integer, String> map = UnifiedMap.newWithKeysValues(1, "1", 2, "2", 3, "3");
Разработчикам, плохо знакомым с библиотекой, эти методы может быть трудно обнаружить, потому что разработчику сначала нужно знать имена соответствующих классов реализации.
Когда в библиотеке были введены неизменяемые коллекции, нам нужно было принять решение, как их создавать. Нам нужен последовательный подход к созданию как изменяемых, так и неизменяемых коллекций, которые следовали бы согласованному соглашению, которое было бы легко освоить разработчикам. Нашим решением было создание выделенных фабричных классов коллекций. Мы решили, что соглашение, которое мы будем использовать с нашими фабричными классами, будет соответствовать имеющимся у нас типам контейнеров с соответствующими типами, оканчивающимися на s. Итак, List
(s), Set
(s), Map
(s) и т. Д. Мы стремимся к хорошей симметрии здесь, чтобы мы могли оправдать ожидания разработчиков. Вот эквивалентный код для создания изменяемых экземпляров коллекции с использованием фабричных классов.
MutableList<String> list = Lists.mutable.with("1", "2", "3"); MutableSet<String> set = Sets.mutable.with("1", "2", "3"); MutableMap<Integer, String> map = Maps.mutable.with(1, "1", 2, "2");
Если вы хотите создать пустые изменяемые коллекции, просто используйте метод empty()
.
MutableList<String> list = Lists.mutable.empty(); MutableSet<String> set = Sets.mutable.empty(); MutableMap<Integer, String> map = Maps.mutable.empty();
Если вам нужен более лаконичный вариант для создания коллекций, вы можете использовать класс Iterables со статическим импортом. Тогда вы можете написать следующее.
MutableList<String> list = mList("1", "2", "3"); MutableSet<String> set = mSet("1", "2", "3"); MutableMap<Integer, String> map = mMap(1, "1", 2, "2", 3, "3");
Методы «m» являются сокращением от «изменяемый», а также существуют методы «i», сокращенно от слова «неизменяемый». .
Все изменяемые интерфейсы в коллекциях Eclipse расширяют соответствующие изменяемые интерфейсы в JDK. Итак, MutableList
- это java.util.List
, MutableSet
- это java.util.Set
и т. Д.
Изменяемые фабрики будут возвращать наиболее конкретный тип (например, MutableList
), но вы можете использовать более абстрактный тип (например, java.util.List
).
List<String> list = Lists.mutable.with("1", "2", "3"); Set<String> set = Sets.mutable.with("1", "2", "3"); Map<Integer, String> map = Maps.mutable.with(1, "1", 2, "2", 3, "3");
Заводские методы, добавляемые в Java 9, будут выглядеть следующим образом.
List<String> list = List.of("1", "2", "3"); Set<String> set = Set.of("1", "2", "3"); Map<Integer, String> map = Map.of(1, "1", 2, "2", 3, "3");
Разница в том, что указанные выше методы возвращают неизменяемые экземпляры с изменяемыми интерфейсами.
Если вы хотите использовать интерфейсы java.util.Collection и хотите, чтобы возвращаемые экземпляры были неизменяемыми, как приведенные выше фабричные методы Java 9, вы можете использовать метод asUnmodifiable()
, доступный для всех изменяемых коллекций в Eclipse Collections.
List<String> list = Lists.mutable.with("1", "2", "3").asUnmodifiable(); Set<String> set = Sets.mutable.with("1", "2", "3").asUnmodifiable(); Map<Integer, String> map = Maps.mutable.with(1, "1", 2, "2", 3, "3").asUnmodifiable();
Если вы хотите, чтобы они синхронизировались, вы можете использовать asSynchronized()
.
List<String> list = Lists.mutable.with("1", "2", "3").asSynchronized(); Set<String> set = Sets.mutable.with("1", "2", "3").asSynchronized(); Map<Integer, String> map = Maps.mutable.with(1, "1", 2, "2", 3, "3").asSynchronized();
Ниже показаны все фабрики для коллекций изменяемых объектов, которые доступны в Коллекциях Eclipse.
MutableList<T> list = Lists.mutable.empty(); MutableSet<T> set = Sets.mutable.empty(); MutableSortedSet<T> sortedSet = SortedSets.mutable.empty(); MutableMap<K, V> map = Maps.mutable.empty(); MutableSortedMap<K, V> sortedMap = SortedMaps.mutable.empty(); MutableStack<T> stack = Stacks.mutable.empty(); MutableBag<T> bag = Bags.mutable.empty(); MutableSortedBag<T> sortedBag = SortedBags.mutable.empty(); MutableBiMap<K, V> biMap = BiMaps.mutable.empty(); MutableListMultimap<K, V> multimap = Multimaps.mutable.list.empty(); MutableSetMultimap<K, V> multimap = Multimaps.mutable.set.empty(); MutableBagMultimap<K, V> multimap = Multimaps.mutable.bag.empty();
Eclipse Collections также поддерживает контейнеры для всех восьми примитивных типов Java. Чтобы обеспечить хорошую симметрию с их аналогами объектов, также существуют фабричные классы для всех изменяемых примитивных типов контейнеров.
MutableIntList list = IntLists.mutable.empty(); MutableIntSet set = IntSets.mutable.empty(); MutableIntBag bag = IntBags.mutable.empty(); MutableIntStack stack = IntStacks.mutable.empty(); // supports all combinations for all 8 primitives MutableIntIntMap map = IntIntMaps.mutable.empty(); MutableIntObjectMap<V> map = IntObjectMaps.mutable.empty(); MutableObjectIntMap<K> map = ObjectIntMaps.mutable.empty();
Есть фабрики для всех примитивных типов для всех типов контейнеров. Изменяемые примитивные контейнеры также имеют неизменяемые и синхронизированные версии, чтобы обеспечить хорошую симметрию со своими объектными аналогами.
MutableIntList list = IntLists.mutable.with(1, 2, 3).asUnmodifiable(); MutableIntList list = IntLists.mutable.with(1, 2, 3).asSynchronized();
Фабрики коллекций в Eclipse Collections работают со всеми версиями Java вплоть до версии 5. Если вы хотите использовать фабрики коллекций с версиями Java до Java 8, вам нужно будет использовать Eclipse Collections 7.x. Eclipse Collections 8.x совместим только с Java 8+. Обе коллекции Eclipse 7.x и 8.x работают с Java 8.
С из или из с
Все примеры, которые я показал до сих пор, в которых используется «с», также могут быть записаны с использованием «из». В битве имен между «с» и «из» было двое победителей. Таким образом, вы можете написать следующее, если предпочитаете вместо. FWIW, подход «с» больше соответствует стилю Smalltalk.
List<String> list = Lists.mutable.of("1", "2", "3"); Set<String> set = Sets.mutable.of("1", "2", "3"); Map<Integer, String> map = Maps.mutable.of(1, "1", 2, "2", 3, "3");
Я думаю, что сейчас хорошее место, чтобы остановиться. Во второй части этой серии блогов я дам обзор неизменяемых фабрик, доступных для коллекций Eclipse.
Коллекции Eclipse открыты для взносов. Если вам нравится библиотека, вы можете сообщить нам об этом, отметив ее на GitHub.