Как стать автором
Обновить

Комментарии 24

А зачем вам Lombok в Kotlin проектах?

Если проект имеет давнюю историю, то под котлин его можно перевозить по частям. Тогда для частей, написанных на java и использующих ломбок, нужна либо деломбокизация, либо заставить дружить ломбок с котлином при сборке проекта

либо разделить сборку на 2 этапа - сперва ту часть кода, в которой Lombok, а потом всё остальное - мы в своё время пошли именно по такому пути

Уже ответили аналогично. Переводили на котлин по частям. Когда наткнулись на эту особенность работы с Lombok - скорректировали порядок перевода, чтобы мухи отдельно, слоны отдельно

А какой профит мы получаем?

Меньше ошибок с null в новом коде, более богатая стандартная библиотека, выразительный язык. Нас больше интересовали подводные камни. Спорить о том какой язык лучше или хуже - можно очень долго)

Вопреки заявленному разработчиками, интеграция с джавой и ее экосистемой далеко не бесшовная. Цена за "удобство" -- общее усложнение билда (соответственно увеличивающаяся "хрупкость"), наличие подводных камней и лишнего геморроя практически с любой библиотекой. К слову, null -- это одна из самых распространенных, но наиболее легко отлаживаемых ошибок. Поэтому формальный смысл данной затеи на мой взгляд очень сомнителен. Котлин оптимально использовать в "чистом" проекте по возможности с нативной котлиновской экосистемой (пусть и небольшой), либо с джавовыми библиотеками, где заявлена поддержка Kotlin.

null - легко выявляется на продакшене, а при разработке можно и пропустить за цепочкой вызовов методов/свойств или просто по лени с мыслью "да, там null, никогда не будет, я в этом уверен".

А Котлин же вынудит тебя обратить на это внимание, иначе проект просто не будет компиляться.

Нативной jave бы перенять эту работу с null-типами, было бы здорово.

привычка объявлять переменные final сводит появление null к минимуму

Как минимум писать меньше кода, как сказал один мой знакомый: "Зачем писать на Java, если есть Kotlin".

В Kotlin очень много "синтаксического сахара", который позволяет очень сильно сократить код и сделать его более читабельным.

Для логгирования использую

inline fun <reified T:Any> loggerFor(): Logger = LoggerFactory.getLogger(T::class.java)

и потом в классах:

    val log = loggerFor<AccessController>()

Зачем ради одной строчки тянуть зависимость, которая мне больше не для чего не нужна?

она даёт больше 1 строчки. например Lazy-логгирование, когда значения вычисляются только если включен необходимый уровень логгирования или удобную обёртку к MDC

MDC это одна строчка со стандартным апи:

MDC.put("username", username)

Lazy - тоже стандартный апи:

log.info("Searching responses with query: {}...", q) 

MDC это одна строчка со стандартным апи

как минимум 2 строчки - добавить, а потом ещё и удалить по завершению контекста. При этом, не забыть вернуть предыдущее значение, если такой параметр MDC уже был ранее - это ещё N строк кода.
гораздо удобнее "завернуться" в блок, который это сделает за вас:

withLoggingContext("USER_ID" to userEntity.id) {
  // code
}

Но если вам хватает 1 строчки кода - это хорошо

Lazy - тоже стандартный апи:

Не совсем. В этом случае всегда будет вызываться q.toString(). Если, например, есть логирование entity - это может вызвать запрос в базу.

Когда используем библиотеку

logger.debug { "hello $message" }

message.toString() вызывается только если здесь соответствующий уровень логирования

Better yet, use parameterized messages

There exists a very convenient alternative based on message formats. Assuming entry is an object, you can write:

Object entry = new SomeObject();logger.debug("The entry is {}.", entry);

After evaluating whether to log or not, and only if the decision is affirmative, will the logger implementation format the message and replace the '{}' pair with the string value of entry. In other words, this form does not incur the cost of parameter construction in case the log statement is disabled.

Спасибо. Пропустил эту возможность. Согласен, что она так же удобная как Kotlin-шаблоны

усложните вызов до:

logger.debug("The child entry is {}.", entry.child);

в какой момент будет получен child?

Если поле, как у вас записано, то сразу (извлечение ссылки на поле - это вычисление смещения, почти бесплатно). Если же у вас метод с вложенной логикой, то можно Supplier использовать:

logger.debug("The child entry is {}.", entry::child);

А я пока так делаю:

companion object {

private val log = LoggerFactory.getLogger(this::class.java)

}

Да, я тоже с этого начинал, потом родил однострочечнек свой, и на этом успокоился :)

так еще проще
```
val logster: ReadOnlyProperty<Any, Logger> get() = LoggerDelegate()

class LoggerDelegate : ReadOnlyProperty<Any, Logger> {

lateinit var logger: Logger

override fun getValue(thisRef: Any, property: KProperty<*>): Logger {

if (!::logger.isInitialized) logger = LoggerFactory.getLogger(thisRef.javaClass)

return logger

}

}
```
и потом
```private val logger by logster```

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории