Узнайте о поддержке примитивных коллекций в Eclipse Collections.
Пороки бокса на Яве
В Java есть восемь примитивных типов. Это boolean
, byte
, char
, short
, int
, float
, long
и double
. Каждый примитивный тип имеет соответствующую оболочку объекта. Это Boolean
, Byte
, Character
, Short
, Integer
, Float
, Long
и Double
. Упаковка - это процесс принятия примитивного значения и сохранения его в экземпляре соответствующего ему типа оболочки. Autoboxing - это функция, добавленная в Java 5. Autoboxing позволяет автоматически заключать примитивное значение в экземпляр соответствующего ему класса оболочки, не требуя от разработчиков явного написания какого-либо кода для выполнения упаковки.
Для получения дополнительной информации об автобоксовке и распаковке, пожалуйста, обратитесь к разделу руководства по Java Автобоксинг и распаковка.
Измерение размеров объектов в JVM - хорошая статья и введение в использование Java Object Layout, который является проектом OpenJDK Code Tools.
Почему бокс - зло?
Бокс на Яве - это почти пустая трата времени. Разработчики чаще всего заботятся о примитивном значении в оболочке, а не о самой оболочке. Оболочка существует прежде всего для того, чтобы разработчики могли использовать примитивное значение в коллекциях. Удобство автобокса - зло, потому что оно позволяет разработчику незаметно генерировать мусор оболочки, который может отрицательно сказаться на производительности их приложений.
Спасибо, пожалуйста, никаких скрытых ящиков!
Коллекции Eclipse помогает предотвратить создание разработчиками скрытых ящиков в куче Java, предоставляя им полный контроль с помощью полного набора примитивных коллекций. Сегодня в Eclipse Collections есть несколько примитивных структур данных, которые работают со всеми восемью примитивными типами.
В API есть поддержка преобразования между коллекциями объектов и примитивов.
Подобно реализации в коллекциях объектов, возвращаемые типы являются ковариантными и специализированными по подтипам. Я продемонстрирую это, показав примеры API как для изменяемых, так и для неизменяемых типов.
Визуализация примитивной иерархии типов коллекции
Генерация кода во время сборки
Если восемь раз воспроизвести и поддерживать исходный код приведенных выше диаграмм кажется невыполнимой задачей, вы будете правы. Хитрость в том, что мы кодируем примитивные типы коллекций из файлов шаблонов. Eclipse Collections использует StringTemplate для генерации большей части исходного кода Java для своих примитивных коллекций. Это происходит во время сборки. Таким образом, вы не увидите исходные файлы .java для примитивных коллекций в GitHub. Однако вы увидите шаблоны с расширением .stg в модуле eclipse-collections-code-generator
.
Покажи мне код
Я приведу примеры всех примитивных структур данных для одного примитивного типа - int
. Существует очень богатый API для сбора примитивов, и я продемонстрирую немало методов в коде. Будьте готовы прокрутить, так как примеров очень много.
Оглавление
Щелкните ссылку ниже, чтобы перейти к разделу. Щелкните ссылку TOC внизу каждого раздела, чтобы вернуться сюда.
- "Список"
- "Установленный"
- "Сумка"
- "Куча"
- "Карта"
- "Ленивый"
- Синхронизированный
- Неизменяемый
- "Нить"
- Затраты на память
Примитивный список
Примитивные List
реализации в Eclipse Collections основаны на массивах. Есть как изменяемые, так и неизменяемые списки примитивов. Следующий код продемонстрирует API, доступные для изменяемых и неизменяемых типов. В иерархии пакетов появится шаблон, который упростит обнаружение различных типов в среде IDE.
Примечание. IntInterval
- это ImmutableIntList
.
Примитивный набор
Примитивные реализации Set
в коллекциях Eclipse основаны на массивах и используют открытую адресацию. Есть как изменяемые, так и неизменяемые примитивные наборы. Следующий код продемонстрирует API, доступные для изменяемых и неизменяемых наборов.
Примитивная сумка
Примитивные реализации Bag
в Коллекциях Eclipse поддерживаются примитивом Maps
. Например, IntBag
будет поддерживаться IntIntMap
. где первый int
- это тип Bag
, а второй int
- количество каждого значения в Bag
. Существуют как изменяемые, так и неизменяемые примитивные пакеты. Следующий код продемонстрирует API-интерфейсы, доступные для изменяемых и неизменяемых пакетов.
Примитивный стек
Примитивные реализации Stack
в коллекциях Eclipse поддерживаются примитивным массивом. Существуют как изменяемые, так и неизменяемые примитивные стеки. Следующий код продемонстрирует API-интерфейсы, доступные для изменяемых и неизменяемых стеков.
Примечание. Stack
не является Collection
, поэтому Stack
не имеет дополнительных методов изменения, таких как add
, addAll
, remove
, removeAll
или retainAll
. В коллекциях Eclipse у Stack
есть богатый итеративный набор методов (например, select
, reject
, collect
и т. Д.).
Примитивная карта
Примитивные Map
реализации в Eclipse Collections поддерживают все комбинации типов ключей и типов значений. В случае, когда типы ключей и значений совпадают, и ключи, и значения хранятся в одном массиве. В случаях, когда типы ключа и значения различаются, они будут храниться в отдельных массивах. Есть как изменяемые, так и неизменяемые примитивные карты. Следующий код продемонстрирует API, доступные на изменяемых и неизменяемых картах.
Примечание. Map
типов в коллекциях Eclipse имеют Iterable
значение. Таким образом, IntIntMap
также является IntIterable
и поддерживает полный набор методов, доступных на IntIterable
.
Примитивный ленивый итерабельный
Каждая примитивная коллекция может вернуть себе ленивое представление, вызвав asLazy
. Следующий код покажет некоторые из ленивых операций, доступных на LazyIntInterable
.
Примитивные синхронизированные коллекции
Каждая изменяемая примитивная коллекция может возвращать синхронизированное представление о себе, вызывая asSynchronized
. Синхронизированные коллекции небезопасно использовать с iterator
без явной блокировки. Однако существует большое количество атомарных операций, доступных для типа, которые принимают блокировки внутри методов.
Примитивные неизменяемые коллекции
Каждая изменяемая примитивная коллекция может вернуть неизменяемое представление о себе, вызвав asUnmodifiable
. Неизменяемые коллекции небезопасно использовать с методами изменения, такими как add
, remove
и т. Д., Поскольку они будут генерировать UnsupportedOperationException
. Однако в коллекциях доступно большое количество методов, доступных только для чтения.
Примитивная строка
Eclipse Collections имеет три простых String
адаптера - CharAdapter
, CodePointAdapter
, CodePointList
. Эти типы предоставляют богатые примитивные протоколы для символов или кодовых точек в String
. CharAdapter
и CodePointAdapter
- чистые взгляды на String
. CodePointList
фактически кэширует кодовые точки из String
в ImmutableIntList
.
Затраты на память
Упаковка примитивов в оболочки требует значительных затрат памяти. В следующей таблице показана сравнительная стоимость памяти для хранения 1 миллиона значений int как в примитивных, так и в упакованных структурах данных. Я могу потратить некоторое время на то, чтобы поместить это в диаграмму, но подумал, что рано поделюсь этими необработанными сравнениями вместе с кодом, который я использовал для их вычисления.
Примечание. Самый простой сборщик мусора - это мусор, который никогда не создавался.
В ожидании Валгаллы
Я в восторге от обещания проекта Valhalla для Java. Возможно, вы ждете, пока проект Valhalla улучшит производительность кода, который вы пишете. Я искренне хотел бы дождаться Валгаллы. Это, вероятно, избавило бы меня и многих других, кто работает над коллекциями Eclipse и другими примитивными библиотеками коллекций, от большого количества работы. К сожалению, ждать появления расширенных возможностей в будущей версии языка программирования - вариант не для всех.
Мы добавили примитивные коллекции с богатым API в Коллекции Eclipse почти девять лет назад. Мы увидели выдающиеся преимущества. Мы надеемся, что признание этих преимуществ помогло сохранить фокус и развитие JEP 218: обобщения над примитивными типами.
Я рада, что мы не подождали. Уроки, которые мы извлекли и продолжаем усваивать в примитивном пространстве коллекций, могут помочь в разработке и разработке проекта Valhalla.
Мысли о недостающих структурах данных в Java
Даже после того, как мы доберемся до Валгаллы на Java, в Java будет много отсутствующих структур данных. Я писал о необходимости возрождения пространства коллекций Java в прошлом году. Возможности обширной библиотеки коллекций Java огромны. Это очевидно по размеру Коллекций Затмения. Несмотря на это, мы продолжим работу с коллекциями Eclipse и будем помогать развивать пространство коллекций Java.
Надеюсь, вам понравился мой трехчастный обзор некоторых недостающих структур данных Java, о которых вам никто никогда не рассказывал. Теперь вы можете сказать, что о некоторых из них вам кто-то рассказал.
Особая благодарность Сирише Прата за вычитку черновой версии этого блога.
Я руководитель проекта и ответственный за проект OSS Коллекции Eclipse в Eclipse Foundation. Eclipse Collections открыта для пожертвований. Если вам нравится библиотека, вы можете сообщить нам об этом, отметив ее на GitHub.
Другие статьи по программированию на Java, которые могут вам понравиться:
Полный план развития Java-разработчика
10 вещей, которые должен выучить Java-программист
10 языков программирования, которые вы можете изучить
10 инструментов, которые должен знать каждый Java-разработчик
10 причин изучать языки программирования Java в 2021 году
Мои любимые бесплатные курсы программирования для начинающих
10 бесплатных Курсы по структуре данных и алгоритмам
7 лучших курсов по структуре данных и алгоритмам для начинающих
50+ вопросов для интервью по структуре данных и алгоритмам