Комментарии 63
А что нам по поводу range предлагает стандартная библиотека?
EliminateAutoBox
оптимизация здесь сработала, скорее, повезло. Она чаще не работает, чем работает :) Даже на свежайшей JDK 17-ea простой пример отсюда (setPrimitive) по-прежнему аллоцирует лишний объект.Зато если вместо автобоксинга написать
new Integer(i)
, то сразу всё хорошо оптимизируется. На этом фоне очень обидно, что конструкторы обёрток задеприкейтили, не предоставив сопоставимую по скорости альтернативу :(От new Integer(i)
на обычном кроваво-энтерпрайзном проекте "Сонар" кондратий хватит
То, что EliminateAutoBox оптимизация здесь сработала, скорее, повезло
Может повезло, а может и специально такие сценарии обрабатывали.
не предоставив сопоставимую по скорости альтернативу :(
Думаю, можно создать свою тривиальную обёртку, если где-то необходимо работать с боксами, а Integer.valueOf не дожимает производительность.
К сожалению, обертка не всегда подходит и иногда нужен именно тип Integer
, поэтому приходится использовать new Integer(i)
.
Интересно, получится ли в итоге такой конструктор удалить в будущих версиях Java, не сломав существенную часть экосистемы
обертка не всегда подходит и иногда нужен именно тип Integer, поэтому приходится использовать new Integer(i)
А разве есть разница между типом возвращаемым из new Integer(i)
и Integer.valueOf(i)
?
А я вот наоборот, люблю синтаксический сахар, но при этом конкретно в такой формулировке range
пользы в своём проекте не вижу. Потому для меня там тоже нет подходящего ответа — я использую Java 14+, но не пишу в таком стиле, и пока не вижу смысла начинать писать в таком стиле.
Какие недостатки вы видите?
Да не то чтобы тут были какие-то прямо общие недостатки.
Мне практически нигде и никогда за последние, скажем так, три года не было нужды писать
for (int i = J; i < K; i+=N) { ... }
при любых J, K и N. В отличие от, к примеру for (var el : c) {...}
.
Из этого следует, что такая утилита мне просто не нужна ввиду отсутствия нужды в Range
как Iterable<N>
. Зато есть нужда в Range
как представлении [N;K)
и прочих подобных формах, включая случаи когда N и K — это даты, время или вообще произвольный Comparable
.
Мне практически нигде и никогда за последние, скажем так, три года не было нужды писать
Хм. Удивительно. А мне довольно часто приходится писать и читать такие циклы. Видимо, задачи сильно разные.
задачи сильно разные.
Да, самый вероятный вариант. В моём случае все ограничения по количеству находятся за пределами домена программы, а программа должна либо обработать вообще всё, что ей придёт, либо обработать всё, что пришло до срабатывания предиката (takeWhile
), либо отбросить все элементы, кроме первого.
Интересно, появится ли в яве когда-нибудь возможность самостоятельно определять синтаксические конструкции для своего проекта, иными словами возможность написать что-то вроде
define (int x...int y) => MyUtilityClass.range(x, y);
чтобы компилятор самостоятельно мог привести
for (i : 0...10) {
//...
}
к
for (i : range(0, 10)) {
//...
}
?
Джависты очень ревниво относятся к синтаксису языка и очень неохотно затаскивают даже элементарный сахар. А тут не просто сахар, а целый язык шаблонов предлагаете. Очень сомнительно, что сделают нечто подобное.
Такого не будет, не переживайте.
Джависты очень ревниво относятся к синтаксису языка и очень неохотно затаскивают даже элементарный сахар.
С одной стороны вроде да, а с другой стороны Ломбок большинство разработчиков затащило только в путь.
Разработчики языка не равны пользователям языка. Ну и насчёт большинства ещё неизвестно.
Расстояние между разработчиками Lombok и пользователями языка Java гораздо меньше, чем между разработчиками Kotlin или Scala и пользователями этих языков.
А что касается большинства, я конечно никогда не видел результатов опросов, но могу отослать к выступлениям таких авторитетов, как Барух Садогурский или Евгений Борисов. По ним создаётся ощущение, что Lombok повсюду уже давно и надолго.
По смыслу Ломбок мало отличается от butterknife или di типа dagger. Просто еще одна «библиотека», которая делает какую-то полезную магию.
В проектах, где есть особые требования к качеству кода, обычно ломбок, DI и т.п не используют.
В проектах, где есть особые требования к качеству кода, обычно ломбок, DI и т.п не используют.
А как DI снижает качество кода?
Никто вам не запрещает написать собственный препроцессор для разворачивания таких конструкций и прочих макросов. Через Gradle или maven вопрос решается элементарно.
Но это уже будет не Java, а что-то другое. Тогда лучше перейти на другой язык, где есть уже инструментальная поддержка.
Но это уже будет не Java, а что-то другое.
Авторов и пользователей Lombok это не остановило, а скорее вдохновило ))
Тогда лучше перейти на другой язык, где есть уже инструментальная поддержка.
Я очень часто встречаюсь с рекомендациями не использовать Lombok, а перейти на Kotlin. Потому что Lombok для джавы чужеродный, а в Kotlin фичи уже есть.
И пока что мне ещё никто не ответил, как в Kotlin решаются проблемы с Entity или как сделать билдер, или как преобразовать неизменяемый объект в билдер, а потом из билдера получить новый объект. Или ещё 100500 юскейсов которые отрабатывает Lombok.
Но допустим Kotlin, или какой-то другой язык завтра выровняется по фичам с Lombok. Послезавтра какой-нибудь разработчик добавит в Lombok генератор equals и hashCode для Entity и Lombok опять убежит вперёд. А когда это всё появится в другом языке совершенно неизвестно. Да и вообще — появится ли? Если экстраполировать будущее исходя из текущего положения дел — то очевидно, что нет.
Это всё долгий и отдельный разговор, но
И пока что мне ещё никто не ответил, как в Kotlin решаются проблемы с Entity или как сделать билдер, или как преобразовать неизменяемый объект в билдер, а потом из билдера получить новый объект. Или ещё 100500 юскейсов которые отрабатывает Lombok.
В Котлине билдеры не нужны вообще. Для этого есть copy.
В Котлине билдеры не нужны вообще. Для этого есть copy.
Вот о чём-то таком я и говорил. copy есть, но для Entity ничего нет и в Lombok или чём-то подобном оно может появиться, а в Kotlin — врядли. Разговор, конечно, долгий и отдельный и самое главное очевидного и простого ответа найти, скорее всего, не получится.
И пока что мне ещё никто не ответил, как в Kotlin решаются проблемы с Entity
Интересно. А можно проблему с Entity описать?
- Entity должны быть изменяемыми
- Должен существовать конструктор по умолчанию
- equals должен быть заявзан только на
@Id
или только на естественный ключ - Если equals завязан на id, который делается генератором, то он должен возвращать false, если
@Id
== null, а hashCode должен возвращать 31.
Lombok помогает с пунктами 1 и 2, а также 3.
Наверное я упускаю какой то контекст. А апелляция к чему?
К тому, что использовать дата классы в качестве Entity не проще, чем использовать в качестве Entity обычные классы. И тут врядли что-то изменится.
А сделать библиотеку, которая с помощью генерации кода решает эту проблему можно сделать в любой момент и работать будет для любой версии джавы, поддерживающей annotation processing.
Вот прям только что использовал дата классы для того чтобы работать со Spring Data — ничто не помешало.
Только пришлось обозначить поля как изменяемые, вручную написать конструктор без параметров, вручную написать hashCode и equals, а так же toString, правильно?
Может быть я ошибаюсь, но мне кажется, что дата классы в такой ситуации не дают никаких преимуществ по сравнению с обычными.
Нет. Примерно вот так:
@Table("MESSAGES")
data class Message(
val content: String,
val contentType: ContentType,
val sent: Instant,
val username: String,
val userAvatarImageLink: String,
@Id var id: String? = null)
или это не по фен-шую? Не все требования выполняются, да, наверное в каких-то ситуациях надо будет писать свой equals и hashCode.
или это не по фен-шую?
Не по фен шую )). Конструктора без параметров нет. И ещё val это опечатка наверное, да? Или это вообще не Entity и к Jpa никак не относится?
Не все требования выполняются, да, наверное в каких-то ситуациях надо будет писать свой equals и hashCode.
Как будут использоваться Entity в будущем предугадать невозможно, поэтому если не сделать equals и hashCode сразу, то потом замучаешься искать причины непонятного поведения в самые неподходящие моменты.
Используется со Spring Data. JPA — так сразу и надо было сказать :)
Для JPA дата классы конечно же не очень хорошо подходят.
Конструктора без параметров нет.
Так есть же Kotlin no-arg: JPA support
Котлин — бета.
Джава уже релиз.
Вот только у IDE после подобных упражнений начнутся проблемы. И придется после этого писать для нее плагин. И скорее всего, это будет плагин для IDEA, который тоже нужно будет поддерживать. Кому-тот придется расширять файлы синтаксиса для vim, а синтакстическим плагинам вима тоже голову будет переодически сносить. Так что если что-то подобное иметь, то из из коробки либо не иметь вовсе.
Я бы предпочел использовать специализированные стримы.
for (int i: IntStream.range(0, 10)) {
System.out.println(i);
}
И еще я бы хотел опцию компилятора -XX:+TurnOffAutoBoxingUnboxingCompletely.
Добавьте пожалуйста вариант в голосование "Пишу на Kotlin/Scala/Clojure/Other-JVM и мне всё-равно что там в ванильной Java"
(*) Подожду Вальгаллу, чтобы уж наверняка!
Я как человек с компиляторным бэкграундом и хорошо знающий, как работает JIT с его куриными мозгами, не стал бы в критическом коде писать новомодный синтаксис, а всё бы развернул руками. Ещё есть Android (а так же различные способы запустить Java-приложения на iOS) и там уж точно всё работает совсем не так. Так что если нужно писать кроссплатформенный код (например, библиотеку, которую можно использовать на бэкэнде и на Android), да ещё и критический по производительности, я бы точно воспользовался старым добрым синтаксисом. Такие мелочи не особо влияют на читаемость кода, а IDE позволяет быстро его писать. Вот что действительно плохо влияет на читаемость кода — это более глобальные вещи, вроде правильных абстракций, соблюдения принципов вроде SOLID и т.д., а не какие-то отдельно взятые циклы.
Категорически поддерживаю. В целом статья интересна в качестве изучения динамики развития технологии.
Но сколько сотен раз умные люди повторяют, что никогда нельзя закладываться на особенности реализации — этого никто не слышит.
И да, в последнее время все слишком увлеклись потреблением и производством сахара, а качество решений в целом снижается.
Кстати очень хороший поинт. Хотелось бы посмотреть как развертка будет работать для ARM, а так же как оно будет работать после компиляции в нативный код.
Такие преобразования выполняются на платформенно-независимом IR задолго до кодогенерации, поэтому на ARM проблем быть не должно. Но если у кого-нибудь есть ARM под рукой, можете измерить. Что касается компиляции в нативный код — если это делать с помощью GraalVM, то она щёлкает боксинг как орехи уже давно. Там эскейп-анализ и скаляризация наголову выше, чем в C2. Они даже хвастались, что Objects.hash(i, j, k) будет работать с той же скоростью как и явный аналог типа ((31+i)31+j)31+k, то есть они и от массива-варарга, и он боксов в каждом элементе избавляются на раз.
Недавно видел класс, обертка вокруг jdbc из допотопных времен. Чуть ли не предтеча hibernate. Там жуть. 20 лет назад это наверное сокращало написание кода, а сейчас spring все те же проблемы решает аннотацией и парой строк. И не переделать ничего уже, так как ни бюджета ни желания, а софту еще лет 20 жизни предрекли. Переписывать никто не будет.
Вы как-то сильно недооцениваете память программистов. В любом большом проекте есть тысячи внутренних методов, и знакомый с проектом программист обычно помнит и понимает, какой из них что делает, когда читает код. Редко когда требуется заглянуть в документацию. Да и в стандартной библиотеке тысячи методов, и в используемых библиотеках тоже. Пара новых ничего не усложняют. Конечно, было бы удобнее, если бы они появились в OpenJDK, но и свой утилитный класс это не большая проблема. При написании кода можно, кстати, стандартные шаблоны IDE переопределить, чтобы использовать новые методы автоматически.
range(from, to)
, когда мне нужно использовать i
в лямбде внутри тела цикла. В остальных случаях пишу обычный for (int i = ...)
.Все-таки range это в некотором смысле ленивая конструкция, требовать от нее высокой производительности немного странно. А что если нужен range с шагом отличным от единицы? Справится ли JIT?
Анбоксинг в современной Java