Kotlin — примеры кода (рецепты)

Привет! Сегодня никаких тематических записей — просто примеры кода kotlin для решения простых задач. Большинство задач можно решить прочитав внимательно документацию. Но, иногда, примеры приводимые там не очень показательны и малоприменимы к практическим задачам.

Как узнать тип переменной Kotlin?

Узнать, к какому типу относится переменная можно с помощью двух простых свойств class.simpleName и class.qualifiedName. Указываются они через два символа двоеточия.

fun main(args : Array<String>) {    
    val score = 10
    val bool = true
    val key = "Key String"

    // Digit is Int, Bool is kotlin.Boolean, Key is String
    print("Digit is ${score::class.simpleName},Bool is ${bool::class.qualifiedName},Key is ${key::class.simpleName}")
}

Как получить индекс элемента массива Kotlin?

val cars = arrayOf("Ford", "Mazda", "Toyota", "VW")
for(i in cars.indices){
    println("машина с индексом $i - ${cars[i]}")
}
for((index, item) in cars.withIndex()){
    println("тачка с номером $index - $item")
}

val list = listOf<String>("Focus", "RX-8", "Avensis", "Polo")
for(index in list.indices){
    println("модель $index индекс ${list[index]}")
}
for((index, element) in list.withIndex()){
    println("модель $index это $element")
}

Кроме того, есть способы получить индекс с помощью forEachIndexed

val bikes = arrayOf("Kawasaki", "Honda", "BMW", "Aprilia")
    bikes.forEachIndexed { bike, index ->
        println("Байк $bike индекс $index")
    }
}

Генерируем MD5 hash в Kotlin

MD5 — один из самых распространенных алгоритмов хеширования. MD5 хеш содержит 128 бит и представляется в виде последовательности из 32 шестнадцатеричных цифр. С помощью него можно проверять целостность и подлинность скачанных файлов, хешировать пароли или же для идентификации пользователи.

var md5 = { input: String ->
    val md = MessageDigest.getInstance("MD5")

    BigInteger(1, md.digest(input.toByteArray()))
        .toString(16)
        .padStart(32, '0')
}

// d52387880e1ea22817a72d3759213819
println(md5("Java"))

Выше пример простой lamdba, которая принимая строку возвращает искомый хеш с помощью MessageDigest. Biginteger тут нужен потому что число перед преобразованием в строку получается очень большим, и простого Int тут уже мало.

Kotlin callback пример кода

Теперь посмотрим как можно создать функцию обратного вызова — callback. Здесь есть два решения — с помощью интерфейса (классическая реализация) и при использовании Unit. Мне больше нравится второй вариант.

Допустим, у нас есть способ получения данных из Сети — getData(link: String), который в качестве параметра принимает ссылку и возвращает строку. Тогда в нашей функции первым параметром мы передаем ссылку для него, а вторым — переменную callback, которая передает String в Unit (функциональный тип)

inline fun loadCallback(url: String, callback: (String?) -> Unit) {
    callback(getData(url))
}

Теперь, для того чтобы получить данные асинхронно, делаем так — передали ссылку, вторым параметром вызвали lambda, в которой собственно и вывели результат. Если не называть переменную result, то вместо нее будет стандартный котлиновский it

loadCallback("https://jsonplaceholder.typicode.com/comments/1", { result ->
    println(result)
})

Parallel requests Kotlin

Параллельные запросы в Котлин можно выполнить разными способами. Можно использовать parallelStream из Java, но как мне кажется, лучшим решением будет «заюзать» async await из корутин.

Подключаем корутины в проект с помощью Maven или Gradle. Теперь допустим нам нужно получить два ответа с разных серверов одновременно.

coroutineScope {
    val comm1 = async { getHttpAsync("https://jsonplaceholder.typicode.com/comments/9") }
    val comm2 = async { getHttpAsync("https://jsonplaceholder.typicode.com/comments/2") }
    println("${comm1.await()} \n ${comm2.await()}")
}

Здесь мы объявляем coroutineScope, в котором вызываем билдер async { }. Чтобы получить результат требуется вызвать метод await(). Но что если мы хотим получить одновременно 5 или 10 комментариев? Не проблема!

suspend fun <T>asyncHttp(range: Iterable<T>) = coroutineScope {
    range.map { elem ->
        async(Dispatchers.IO) {
            getHttpAsync("https://jsonplaceholder.typicode.com/comments/$elem")
        }
    }.awaitAll()
}

Функция asyncHttp получает на вход переменную типа Iterable, которая может быть как диапазоном, так и списком. Далее, мы проходимся с помощью map по всем элементам и получаем от каждого Deferred с помощью getHttpAsync (функция, которая получает данные из Сети, у Вас может быть своя реализация). Затем, когда итерация закончится awaitAll() выдает нам одновременно все результаты, вот и получается по сути параллельный запрос в Kotlin. Проверим результат.

fun main() {
    val time5 = measureTimeMillis {
        runBlocking {
           println(asyncHttp(10 downTo 0))
        }
    }
    println("AsyncHTTP: $time5")
}

Заодно проверим и время выполнения. Достаточно быстро, особенно в сравнении с реализацией parallel map, которая «гуляет» по Сети.

Вот и все. В следующих статьях я обязательно подберу еще несколько полезных примеров по использованию языка Котлин — работа с БД, обработка ошибок, получение асинхронных данных из Интернета и так далее.

Всем пока!

Оставить ответ