| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java: Общие вопросы > Почему в Set-е нету get-а? |
| Автор: Shklyar 16.7.2018, 23:52 |
| Почему в Set-е нету get-а? |
| Автор: Се ля ви 16.7.2018, 23:55 |
| Индексации нет, порядку тоже нет. Что бы ты хотел, что бы такой метод выдавал? |
| Автор: Shklyar 17.7.2018, 01:15 |
| Хотел бы по получить obj, который eq, приблизительно, как в Map получают значение. Встретил ситуацию, когда часть обьекта определяет уникальность и ее легко повторить, а другая часть хранит дополнительные полезные данные, которые нужно получить. Можно проитерироваться, но пропадает вся прелесть хоть какой реализации Set. |
| Автор: Се ля ви 17.7.2018, 16:05 | ||||||||||||||
| Довольно специфический функционал и вообще - это не корректное использование eq, IMHO (так что соглашусь с LSD)... Но, как говориться, если нельзя, но очень хочется... В общем, если сильно нужно - добавь сам. Java, конечно, не Groovy, не Kotlin и тем более не Scala, что бы поддерживать из коробки extension-method`ы, но могу предложить два довольно корявых, но способа:
Для начала нам нужны зависимости на JUnit5, AssertJ (что бы делать проверки) и Lombok (без него, как, впрочем, и без Vavr`а, я уже давно - как без рук):
Ну и, что бы среда разработки лишний раз не ругалась на Lombok, желательно установить Lombok plugin. Правда, от всего это не спасёт - например, функционал @ExtensionMethod`а он не поддерживает - https://github.com/mplushnikov/lombok-intellij-plugin/issues/21 до сих пор открыто :((( Так что придётся либо мириться с "краснотой" в IDE и code-review tool`е, либо использовать пока только первый способ. Итак, для начала нам нужен объект, по которому будем тестировать:
(Если в друг нет опыта с Lombok`ом, эти аннотации заставят перед компиляцией:
Итак, приступим. Первый вариант - использование неявной типизации при помощи ключевого слова var, появившегося в Java 10 (приём, известный как "Ad-Hock Methods" описан Николаем Парлогом https://blog.codefx.org/java/tricks-var-anonymous-classes/#Ad-hoc-Methods):
Второй способ - через https://projectlombok.org/features/experimental/ExtensionMethod:
У меня все тесты проходят. Надеюсь, разъяснил. Демо-проект (в варианте с Gradle`ом) https://github.com/Vyacheslav-Lapin/extension-methods-in-java. |
| Автор: Shklyar 17.7.2018, 16:20 | ||||||||
Обьекты приходят снаружи, с зависимости. Раньше они были собраны в сет - видимо задумано им быть уникальными. Ранее достаточно было (и было) контейнс, но вот понадобилось посмотреть на обьект, который контейнс. Пришел к Map<T, T>
Интересная конструкция. Исходя из HotSpot имплементации Set, посчитал что получу свой поиск без дополнительных затрат перейдя на Map. Се ля ви, ого, почитаю. |
| Автор: Shklyar 18.7.2018, 12:34 | ||
Спасибо, есть с чем поиграться. Да, очень хочется, но не добавить, а взять. Где-то слышал, что самый надежный код - тот что не написан. Ну а если б хотелось написать, скорее б это был утилитный для сета класс. Посмотрел я метод get - а как там используется встроенный в Set алгоритм поиска?) И еще одно ПОЧЕМУ: почему метод сета add возвращает boolean? Забыл добавить, что такая конструкция понравилась как предохранитель, когда в будущем по неосторожности кто-то захочет что-то сломать. |
| Автор: Се ля ви 19.7.2018, 16:23 | ||||
Никак, я по-простому накидал через монаду - просто что бы работало. Реализуй как надо - я же показывал исключительно как цеплять метод.
Так по сути это и есть второй мной описанный вариант - класс-то утильный с методом get отдельный и выносить можно куда угодно. Потому что в Set`е может уже быть этот объект - и это значит, что добавить (не удалив) его туда не получится. При чём определяется это по методам equals и hashCode, так что в твоём случае "странного" использования equals`а, это значит, что если там есть какой-то объект, который eq с тем, который ты пытаешься положить - ты его туда не положишь. Можно их, конечно, развести по hashCode`ам, но тогда ты теряешь преимущества того самого "встроенного в Set алгоритма поиска". |
| Автор: Shklyar 19.7.2018, 23:32 | ||
Не в моем. Вот посмотрел, и рад бы поругаться, да все тут ок.
Почему в мапе пут возврашает E? Про Lombok интересен такой вопрос: какие проблемы ты встречал или видишь системными? Слышал мнение, что кто-то долго парился с тем, что натворил Lombok. Я особо не встречал, максимум цикличность, которая детектится с первого раза. Как надо, пока, по моим представлениям, не получится. |
| Автор: Се ля ви 20.7.2018, 14:34 | ||||||||||||||||
equals - это проверка на эквивалентность, т.е. с т.з. предметной области - эти объекты - полные аналоги друг друга. То, что туда не обязаны входить все поля, означает, что они не значимы. Я сегодня могу одеть синюю майку, а завтра красную - но это всё равно останусь я и equals меня в синей майке со мной в красной должен выдавать true. Так же и тут - не вхождение полей в проверку по equals`у означает лишь то, что эти поля не являются идентифицирующими и не важны с т.з. предметной области задачи, но ожидания у програмиста, когда он видит, что два объекта equals именно такие - что это по сути один и тот же объект, просто в силу особенностей алгоритма решаемой задачи оказавшийся скопированным в различные области памяти. Это просто удобно, это т.н. pipeline-стиль написания кода. В Java он известен давно по классам StringBuilder/Buffer, но действительно активно применяется, начиная с Java 8 в Stream`ах, CompletableFuture`ах, Optional`ах - тебе нужно что-то сделать с объектом, но перед этим необходимо положить его в мапу по какому-то ключу. Если бы этого поведения не было, то ты кладёшь объект в мапу одной операцией, и только второй делаешь с ним то, что нужно - в итоге у тебя две операции вместо одной со всем сопутствующим гемороем - блок придётся ставить, если это в лямбде, внутри цикла или if`а, в тернарный оператор не воткнёшь... Очень громоздкий код получается и увеличивается количество точек, где можно совершить ошибку.
Lombok - это не магия! Он простой, как топор и делает с твоим кодом совершенно очевидные, элементарные вещи по устранению boilerplate-кода (т.е. такого кода, за которым не стоит принятия решений, а он является тавтологией и его приходится писать просто из-за того, что язык этого требует). Уже достаточно давно был сформулирован принцип борьбы с таким кодом, который получил название "Convention over Configuration" ("Соглашения по конфикурации"), которому мы обязаны прогрессу в Computer Science последние лет 15, поскольку большинство новых разработок в Java-мире - Spring, Maven, Gradle, Lombok, Vavr, а так же языки и инструменты, проектировались в соответствии с этим принципом. Главное правило использования Lombok`а - как только тебе кажется, что Lombok делает что-то непонятное для тебя - применяешь действие "delombok" и смотришь, во что Lombok превратил твой код, пока не поймёшь. Большую часть деломбока вообще берёт на себя плагин к идее (просто кликаешь правой кнопкой мыши на классе и выбираешь Refactor -> Delombok -> {имя интересующей аннотации или "All lombok annotations" для всех}), но если аннотации в этом списке нет, можно использовать мавеновский плагин, вот моя конфигурация:
Посмотри доклад Цикура, он там конечно далеко не про всё рассказывает, но для начала сойдёт - https://youtu.be/VGewqN_x0oQ Что касается недостатков, они, опять же, сейчас (начиная с 10-й Java) теперь присущи и ей самой - это связано с т.н. "type inference" - когда ты вместо типа пишешь в простой Java var, а с lombok`ом - val. Дело в том, что с т.з. читабельности кода для человека это допустимо только в ситуации, когда из правой части выражения очевидна левая. Часто этим злоупотребляют и пишут val/var даже в тех случаях, когда при чтении кода непонятен выводимый из контекста тип переменной. Этого надо избегать. http://openjdk.java.net/projects/amber/LVTIstyle.html, но если подытоживать, то практика должна быть такой: Используйте val/var только если верен хотя бы один пункт из списка:
Лично я только благодаря Lombok`у и Vavr`у в принципе способен ещё писать на Java, от которой без них меня уже просто тошнит. Если бы ты изучил другие языки JVM, типа Groovy, Kotlin`а и тем более Scala`ы, у тебя - поверь - было бы то же самое. И - да, в продакшене я и многие мои коллеги его использовал, использую и, конечно, буду использовать, пока на Java приходится писать. Работаю я старшим разработчиком в EPAM`е, если что - можешь на меня ссылаться. |
| Автор: Shklyar 20.7.2018, 15:04 | ||||
|
| Автор: Се ля ви 20.7.2018, 15:14 | ||
Мда, ошибочка вышла... Я бы на месте разработчиков сделал бы по-другому. Ну тогда не так удобно, как могло бы. Добавлено через 3 минуты и 56 секунд Вообще, на коллекции в Java море критики - у того же Одерского (автор Scala`ы) - почему они с нуля свою библиотеку коллекций написали. Да и в Java многие активно юзают свои библиотеки коллекций - Guava, GoldmanSachs, Apache, Trove... https://habr.com/company/luxoft/blog/256877/. |
| Автор: Shklyar 20.7.2018, 15:21 |
Собственно, да, ответы на мои почему нашел: потому что так сделали. Но было увлекательно поковырять про редко используемые особенности. |
| Автор: rfq 17.8.2018, 19:13 | ||
если посмотреть на `Set<T>` как на `Map` (в котором есть `get()`), то это `Map<T, boolean>`. То есть, подаем объект и в качестве ответа получаем - входит такой объект во множество или нет. Так что метод `get()` в `Set` есть, только называется он `contains()`. |
| Автор: _zorn_ 17.8.2018, 19:26 | ||||
| А вот можно опять насрать на яву ? Вот буквально сегодня надо было быстренько из с++ в qml данные передать. Я уж начал задумываться - это же писец, типы классы и вот это вот все создавать (воздействие явы на мозг). Но нет посмотрел на свой старый код и QVariantHash меня спас. Тупо
И из qml
Ну и нахрена эти сложности со сранным приведением типа ? И утил для конвертации ? Добавлено через 5 минут и 31 секунду Вот только не надо мне гнать что в вашем ынтерпрайзе нету архитектурных ошибок. В итоге вы боритесь с мельницами на ровном месте. |
| Автор: Shklyar 27.8.2018, 17:34 | ||||||
Так ?:
Вроде как, тут не о Java. |