Kotlin — это мощный язык программирования, который предоставляет много функциональных возможностей из коробки. Однако истинная сила Kotlin заключается в его функциях расширения, которые позволяют разработчикам добавлять функциональность к существующим классам и объектам без создания подклассов или изменения исходного кода. Вот 10 полезных расширений Kotlin, которые сделают ваш код более лаконичным и читабельным.
withNotNull
Одна из распространенных проблем, с которой сталкиваются разработчики при работе с нулевыми значениями, — это проверка на null перед выполнением операций. Функция расширения withNotNull упрощает этот процесс, позволяя разработчикам выполнять блок кода только в том случае, если значение не является null.
inline fun <T : Any, R> T?.withNotNull(block: (T) -> R): R? { return this?.let(block) }
Использование:
val nullableValue: String? = null nullableValue.withNotNull { value -> // Code here will only be executed if nullableValue is not null }
toLiveData
LiveData — это data holder класс, который учитывает жизненный цикл и может быть наблюдаем. Функция расширения toLiveData упрощает процесс преобразования Flow в LiveData.
fun <T> Flow<T>.toLiveData(): LiveData<T> { return liveData { collect { emit(it) } } }
Использование:
val flow = flowOf("Hello", "World") val liveData = flow.toLiveData()
notEmpty
Функция расширения notEmpty упрощает процесс проверки того, не пуста ли коллекция.
fun <T> Collection<T>?.notEmpty(): Boolean { return this != null && this.isNotEmpty() }
Более лаконичный способ:
fun <T> Collection<T>?.notEmpty(): Boolean { return this?.isNotEmpty() == true }
Использование:
val list: List<Int> = emptyList() if (list.notEmpty()) { // Code here will only be executed if list is not empty }
getOrThrow
Функция расширения getOrThrow упрощает процесс получения значения из карты и выбрасывает исключение, если ключ не найден.
fun <K, V> Map<K, V>.getOrThrow(key: K): V { return this[key] ?: throw NoSuchElementException("Key $key not found in map") }
Использование:
val map = mapOf("key1" to "value1", "key2" to "value2") val value = map.getOrThrow("key3")
toFormattedString
Функция расширения toFormattedString упрощает процесс форматирования чисел и дат.
fun Int.toFormattedString(): String { return NumberFormat.getInstance().format(this) } fun Long.toFormattedString(): String { return NumberFormat.getInstance().format(this) } fun Date.toFormattedString(): String { return SimpleDateFormat.getDateInstance().format(this) }
Использование:
val number = 1000000 val formattedNumber = number.toFormattedString()
debounce
Debounce упрощает процесс задержки выполнения блока кода до тех пор, пока не пройдет определенное количество времени с момента последнего выполнения блока.
fun View.onClick(debounceDuration: Long = 300L, action: (View) -> Unit) { setOnClickListener(DebouncedOnClickListener(debounceDuration) { action(it) }) } private class DebouncedOnClickListener( private val debounceDuration: Long, private val clickAction: (View) -> Unit ) : View.OnClickListener { private var lastClickTime: Long = 0 override fun onClick(v: View) { val now = SystemClock.elapsedRealtime() if (now - lastClickTime >= debounceDuration) { lastClickTime = now clickAction(v) } } }
Использование:
button.onClick(debounceDuration = 500L) { // Code here will only be executed if 500 milliseconds have passed since the last click }
toBitmap
Функция расширения toBitmap упрощает процесс преобразования drawable в растровое изображение.
fun Drawable.toBitmap(): Bitmap { if (this is BitmapDrawable) { return bitmap } val bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) setBounds(0, 0, canvas.width, canvas.height) draw(canvas) return bitmap }
Использование:
val drawable = ContextCompat.getDrawable(context, R.drawable.my_drawable) val bitmap = drawable.toBitmap()
toUri
Функция упрощает процесс преобразования пути к файлу в Uri.
fun String.toUri(): Uri { return Uri.parse(this) }
Использование:
val filePath = "/storage/emulated/0/Download/my_file.pdf" val fileUri = filePath.toUri()
applyIf
ApplyIf упрощает процесс применения блока кода к объекту только при выполнении определенного условия.
inline fun <T> T.applyIf(condition: Boolean, block: T.() -> Unit): T { return if (condition) { this.apply(block) } else { this } }
Использование:
val number = 5 val formattedNumber = number.applyIf(number > 10) { toFormattedString() }
В заключение следует отметить, что функции расширения Kotlin могут стать мощным инструментом для упрощения кода и повышения его читабельности. Используя эти 10 полезных расширений, вы сможете сделать свой код более лаконичным, эффективным и удобным для сопровождения.