Я выбираю набор кортежей из базы данных и помещаю их в карту. Запрос к базе данных является дорогостоящим.
Не существует очевидного естественного упорядочения элементов на карте, но, тем не менее, порядок вставки имеет значение. Сортировка карты была бы тяжелой операцией, поэтому я хочу избежать этого, учитывая, что результат запроса уже отсортирован так, как я хочу. Поэтому я просто сохраняю результат запроса в LinkedHashMap
и возвращаю карту из метода DAO:
public LinkedHashMap<Key, Value> fetchData()
У меня есть метод, processData
который должен выполнить некоторую обработку на карте - изменение некоторых значений, добавление некоторых новых ключей / значений. Определяется как
public void processData(LinkedHashMap<Key, Value> data) {...}
Однако несколько линтеров (Sonar и т. Д.) Жалуются, что типом «данных» должен быть интерфейс, такой как «Map», а не реализация «LinkedHashMap» ( squid S1319 ).
Так что в основном это говорит о том, что я должен иметь
public void processData(Map<Key, Value> data) {...}
Но я хочу, чтобы сигнатура метода говорила, что порядок отображения имеет значение - это имеет значение для алгоритма processData
- чтобы мой метод не передавался просто какой-либо случайной карте.
Я не хочу использовать SortedMap
, потому что он (из javadocjava.util.SortedMap
) "упорядочен в соответствии с естественным упорядочением его ключей или компаратором, обычно предоставляемым во время создания отсортированной карты".
Мои ключи не имеют естественного порядка , и создание Comparator, который ничего не делает, кажется многословным.
И я все еще хотел бы, чтобы это была карта, put
позволяющая избежать дублирования ключей и т. Д. Если бы не так, это data
могло бы быть List<Map.Entry<Key, Value>>
.
Итак, как мне сказать, что мой метод хочет карту, которая уже отсортирована ? К сожалению, нет java.util.LinkedMap
интерфейса, или я бы использовал это.
источник
if you are new to programming and stumble upon this answer, don't think this allows you to go against best practice because it doesn't.
- Хороший совет, если бы существовала такая вещь, как «лучшая практика». Лучший совет: научитесь принимать правильные решения. Следуйте практике, если это имеет смысл, но позвольте инструментам и властям направлять ваш мыслительный процесс, а не диктовать его.Вы боретесь с тремя вещами:
Во-первых, это библиотека контейнеров Java. Ничто в его таксономии не дает вам способа определить, повторяется ли класс в предсказуемом порядке. Нет
IteratesInInsertedOrderMap
интерфейса, который мог бы быть реализованLinkedHashMap
, что делает проверку типов (и использование альтернативных реализаций, которые ведут себя одинаково) невозможной. Вероятно, так задумано, потому что суть в том, что вы действительно должны иметь дело с объектами, которые ведут себя как абстракцияMap
.Во-вторых, это вера в то, что то, что говорит ваш линтер, должно восприниматься как Евангелие, а игнорирование всего, что оно говорит, - плохо. Вопреки тому, что считается хорошей практикой в наши дни, предупреждения от линтеров не должны препятствовать тому, чтобы ваш код был хорошим. Они побуждают рассуждать о написанном вами коде и использовать ваш опыт и суждения, чтобы определить, оправдано ли предупреждение. Неоправданные предупреждения - это то, почему почти каждый инструмент статического анализа предоставляет механизм, чтобы сказать ему, что вы изучили код, вы думаете, что делаете хорошо, и что они не должны жаловаться на это в будущем.
В-третьих, и это, вероятно, суть этого,
LinkedHashMap
может быть не тот инструмент для работы. Карты предназначены для случайного, а не упорядоченного доступа. Если выprocessData()
просто перебираете записи по порядку и не нуждаетесь в поиске других записей по ключу, вы заставляете конкретную реализациюMap
делать работу aList
. С другой стороны, если вам требуется и то, и другое,LinkedHashMap
это правильный инструмент, потому что известно, что он делает то, что вы хотите, и вы более чем оправданы в этом.источник
OrderedMap
, я точно так же могу сказатьUniqueList
. Пока это какая-то коллекция с определенным порядком итераций, она перезаписывает дубликаты при вставке.Set
ключи только во время создания списка a, чтобы найти их.processData
изменяет карту, заменяя некоторые значения, вводя новые ключи / значения. Таким образом,processData
можно ввести дубликаты, если он работает на чем-то, кромеMap
.UniqueList
(илиOrderedUniqueList
) и использовать это. Это довольно просто, и делает ваше предполагаемое использование более понятным.Если все, от чего вы получаете,
LinkedHashMap
- это возможность перезаписывать дубликаты, но вы действительно используете их как единое целоеList
, то я бы посоветовал лучше связать это использование с вашей собственной пользовательскойList
реализацией. Вы можете ее на основе существующего Java - классе коллекций и просто переопределить любыеadd
иremove
методы , чтобы обновить резервное хранилище и следить ключ для обеспечения уникальности. Если вы дадите этому отличительному имени как, тоProcessingList
станет ясно, что аргументы, представленные вашемуprocessData
методу, должны обрабатываться особым образом.источник
ProcessingList
как псевдоним дляLinkedHashMap
- вы всегда можете решить заменить его чем-то другим позже, если вы оставите публичный интерфейс без изменений.Я слышу, как вы говорите: «У меня есть одна часть моей системы, которая создает LinkedHashMap, а в другой части моей системы мне нужно принимать только объекты LinkedHashMap, которые были созданы первой частью, так как объекты, созданные каким-то другим процессом, выиграли» не работает правильно. "
Это заставляет меня думать, что проблема здесь заключается в том, что вы на самом деле пытаетесь использовать LinkedHashMap, поскольку он в основном соответствует данным, которые вы ищете, но на самом деле его нельзя заменить каким-либо другим экземпляром, кроме тех, которые вы создаете. Что вы на самом деле хотите сделать, так это создать свой собственный интерфейс / класс, который создает ваша первая часть, а ваша вторая часть потребляет. Он может обернуть «реальный» LinkedHashMap и обеспечить получение карты или реализовать интерфейс карты.
Это немного отличается от ответа CandiedOrange тем, что я бы рекомендовал инкапсулировать реальную карту (и делегировать ей вызовы по мере необходимости), а не расширять ее. Иногда это одна из тех священных войн в стиле, но мне кажется, что это не «Карта с какими-то дополнительными вещами», это «Моя сумка полезной информации о состоянии, которую я могу внутренне представить с помощью Карты».
Если бы у вас было две переменные, которые вам нужно было бы передать таким образом, вы, вероятно, создали бы для него класс, не задумываясь об этом. Но иногда полезно иметь класс, даже если это всего лишь одна переменная-член, просто потому, что это логически одно и то же, не «значение», а «результат моей операции, с которой мне нужно что-то сделать позже».
источник
MyBagOfUsefulInformation
будет нужен метод (или конструктор) для заполнения его:MyBagOfUsefulInformation.populate(SomeType data)
. Ноdata
должен быть отсортированный результат запроса. Так что будетSomeType
, если нетLinkedHashMap
? Я не уверен, что смогу сломать этот улов 22.MyBagOfUsefulInformation
DAO не может быть создан или кто-то еще генерирует данные в вашей системе? Зачем вам вообще нужно показывать основную карту остальному коду за пределами производителя и потребителя пакета?MyBagOfUsefulInformation
параметр DAO в качестве параметра: softwareengineering.stackexchange.com/a/360079/52573LinkedHashMap - единственная карта Java, которая имеет функцию порядка вставки, которую вы ищете. Поэтому отказ от Принципа обращения зависимостей заманчив и, возможно, даже практичен. Сначала подумайте, что нужно сделать, чтобы следовать ему. Вот что SOLID попросит вас сделать.
Примечание: замените имя
Ramdal
описательным именем, которое сообщает, что пользователь этого интерфейса является владельцем этого интерфейса. Это делает его авторитетом, который решает, важен ли порядок вставки. Если вы просто называете это,InsertionOrderMap
вы действительно упустили из виду.Это большой дизайн впереди? Возможно, это зависит от того, насколько вероятно, что вы когда-либо будете нуждаться в реализации
LinkedHashMap
. Но если вы не следуете DIP только потому, что это будет огромной болью, я не думаю, что котельная плита более болезненна, чем эта. Это шаблон, который я использую, когда хочу, чтобы неприкасаемый код реализовал интерфейс, которого нет. Самая болезненная часть действительно думает о хороших именах.источник
Спасибо за хорошее предложение и пищу для размышлений.
В итоге я расширил создание нового класса карты, создав
processData
метод экземпляра:Затем я реорганизовал метод DAO, чтобы он не возвращал карту, а вместо этого принимает
target
карту в качестве параметра:Таким образом, заполнение
DataMap
и обработка данных теперь представляет собой двухэтапный процесс, и это нормально, поскольку есть некоторые другие переменные, являющиеся частью алгоритма, которые поступают из других мест.Это позволяет моей реализации Map управлять тем, как в нее вставляются записи, и скрывает требование упорядочения - теперь это деталь реализации
DataMap
.источник
Если вы хотите сообщить, что используемая вами структура данных существует по какой-либо причине, добавьте комментарий над сигнатурой метода. Если в будущем другой разработчик столкнется с этой строкой кода и заметит предупреждение инструмента, он может также заметить комментарий и воздержаться от «исправления» проблемы. Если нет комментариев, то ничто не помешает им изменить подпись.
На мой взгляд, подавление предупреждений ниже, чем комментирование, потому что само подавление не указывает причину, по которой предупреждение было подавлено. Сочетание подавления предупреждений и комментариев также подойдет.
источник
Итак, позвольте мне попытаться понять ваш контекст здесь:
Теперь, что вы в настоящее время уже делаете:
А вот ваш текущий код:
Я предлагаю сделать следующее:
Пример кода
Я предполагаю, что это избавит от предупреждения сонара, а также укажет в подписи конкретный макет данных, требуемый методом обработки.
источник
MyTupleRepository
она создается?)На самом деле этот вопрос - куча проблем, связанных с вашей моделью данных. Вы должны начать распутывать их, по одному. Более естественные, интуитивно понятные решения будут выпадать, если вы попытаетесь упростить каждую часть головоломки.
Проблема 1: Вы не можете зависеть от порядка БД
Ваше описание сортировки ваших данных не ясно.
ORDER BY
предложение. Если вы не потому, что это кажется слишком дорогим, ваша программа имеет ошибку . Базы данных могут возвращать результаты в любом порядке, если вы их не указали; вы не можете полагаться на то, что данные будут возвращаться в порядке совпадения только потому, что вы выполнили запрос несколько раз, и он выглядит так. Порядок может измениться, потому что строки переставляются на диске, или некоторые удаляются, а новые занимают их место, или добавляется индекс. Вы должны указать какой-тоORDER BY
пункт. Скорость бесполезна без правильности.ORDER BY
предложение. В противном случае у вас есть ошибки. Если такого столбца еще не существует, вам нужно добавить его. Типичными параметрами для таких столбцов могут быть столбец с меткой времени вставки или автоинкрементный ключ. Ключ автоинкремента более надежен.Проблема 2: Эффективная сортировка в памяти
После того, как вы убедитесь , что он гарантированно будет возврата данных в порядке , вы ожидаете, вы можете использовать этот факт , чтобы сделать в памяти сортирует гораздо более эффективным. Просто добавьте столбец
row_number()
илиdense_rank()
(или эквивалент вашей базы данных) в набор результатов запроса. Теперь у каждой строки есть индекс , который даст вам прямое указание того, каким должен быть порядок, и вы можете сортировать его в памяти тривиально. Просто убедитесь, что вы дали индексу осмысленное имя (напримерsortedBySomethingIndex
).Виола. Теперь вам больше не нужно зависеть от порядка набора результатов базы данных.
Проблема 3: Вам даже нужно выполнить эту обработку в коде?
SQL на самом деле действительно мощный. Это удивительный декларативный язык, который позволяет вам выполнять множество преобразований и агрегаций в ваших данных. Большинство БД в настоящее время даже поддерживают операции с несколькими строками. Они называются оконными или аналитическими функциями:
OVER
Предложение SQL Server для оконных функцийТебе даже нужно вытащить свои данные в память, как это? Или вы могли бы выполнить всю работу в запросе SQL с помощью оконных функций? Если вы можете сделать всю (или, может быть, даже значительную часть) работы в БД, это просто фантастика! Ваша проблема с кодом исчезнет (или станет намного проще)!
Проблема 4: Вы делаете что к этому
data
?Предполагая, что вы не можете сделать все это в БД, позвольте мне сделать это прямо. Вы берете данные как карту (которая основана на вещах, по которым вы не хотите сортировать), затем вы перебираете их в порядке вставки и модифицируете карту на месте, заменяя значение некоторых ключей и добавляя новые?
Извините, но какого чёрта?
Абоненты не должны беспокоиться обо всем этом . Созданная вами система чрезвычайно хрупка. Требуется всего одна глупая ошибка (возможно, даже сделанная вами, как мы все сделали), чтобы сделать одно маленькое неправильное изменение, и все это рухнет, как колода карт.
Вот, возможно, лучшая идея:
List
.Возможным вариантом может быть создание отсортированного представления, а затем создание карты ключа к индексу . Это позволит вам изменить вашу отсортированную копию на месте, без случайного создания дубликатов.
Или, может быть, в этом есть больше смысла: избавиться от
data
параметра и заставитьprocessData
фактически извлекать его собственные данные. Затем вы можете задокументировать, что вы делаете это, потому что у него очень специфические требования к способу извлечения данных. Другими словами, сделайте функцию владельцем всего процесса, а не только его части; взаимозависимости слишком сильны, чтобы разбить логику на более мелкие куски. (Измените имя функции в процессе.)Может быть, это не сработает для вашей ситуации. Я не знаю без полной детализации проблемы. Но я знаю хрупкий и запутанный дизайн, когда слышу его.
Резюме
Я думаю, что проблема здесь заключается в том, что дьявол кроется в деталях. Когда я начинаю сталкиваться с подобными проблемами, обычно это происходит из-за того, что у меня неправильное представление моих данных для проблемы, которую я пытаюсь реально решить. Лучшее решение - найти лучшее представление , и тогда моя проблема станет простой (возможно, не простой, но прямой) для решения.
Найдите кого-то, кто получает эту точку зрения: ваша задача сводить вашу проблему к набору простых, простых. Затем вы можете создать надежный, интуитивно понятный код. Поговори с ними. Хороший код и хороший дизайн заставляют вас думать, что любой идиот мог придумать их, потому что они просты и понятны. Может быть, есть старший разработчик, у которого есть такое мышление, с которым вы можете поговорить.
источник
select key, value from table where ... order by othercolumn
и должен поддерживать порядок при их обработке. Порядок вставки, на который они ссылаются, - это порядок вставки в их карту , определяемый порядком, используемым в запросе, а не порядком вставки в базу данных . Это становится понятным благодаря их использованиюLinkedHashMap
, которое представляет собой структуру данных, которая имеет характеристики как пары a, такMap
иList
пары ключей и значений.order by
пункт в запросе, но это не является тривиальным ( не толькоorder by column
), поэтому я хочу , чтобы избежать повторной реализации сортировки в Java. Хотя SQL является мощным (и мы говорим здесь о базе данных Oracle 11g), природаprocessData
алгоритма значительно упрощает его выражение в Java. И да, «порядок вставки» означает « порядок вставки карты », то есть порядок результата запроса.