Avatar ·

Как преобразовать строку в тип Long в Kotlin? Безопасные способы и обработка ошибок

Всем привет! Я только начал изучать Kotlin после Java, и у меня возникла проблема с преобразованием строки в число типа Long. Мне нужно прочитать числовое значение из текстового поля в приложении и выполнить с ним арифметические операции.

Вот пример моего кода:

val input = "1234567890123"
val number: Long = input.toLong()
println(number * 2)

Это работает, когда строка гарантированно содержит корректное число. Но что, если пользователь введёт что-то вроде "abc123" или "12.34"? Тогда программа вылетает с NumberFormatException. В Java я использовал try-catch или проверял через Long.parseLong, но в Kotlin есть какие-то более элегантные встроенные методы?

Ещё вопрос: как обрабатывать случай, когда строка может быть null? Например, когда данные приходят из внешнего API или базы данных. В Kotlin же есть нулл-безопасность, наверное, есть специальные функции?

Буду благодарен за примеры кода с пояснениями. Заранее спасибо!

<<>>

Базовое преобразование: toLong()

Самый простой способ — использовать метод toLong(). Он выбрасывает NumberFormatException, если строка не является валидным целым числом:

val str = "123456789"
val number: Long = str.toLong()
println(number) // 123456789

Безопасное преобразование: toLongOrNull()

Kotlin предоставляет встроенную функцию toLongOrNull(), которая возвращает null вместо исключения, если преобразование невозможно. Это идеальное решение для пользовательского ввода:

val userInput = "abc123"
val number: Long? = userInput.toLongOrNull()
println(number) // null (без исключения)

// Пример с проверкой
val safeInput = "987654321"
val safeNumber = safeInput.toLongOrNull()
if (safeNumber != null) {
    println("Успех: $safeNumber")
} else {
    println("Ошибка: неверный формат")
}

Обработка null-строк

Если строка может быть null, используйте toLongOrNull() в паре с оператором безопасного вызова ?. или элвис-оператором ?::

val nullableStr: String? = null
val result = nullableStr?.toLongOrNull() ?: 0L
println(result) // 0

// Или с более сложной логикой
val fromApi: String? = "123"
val parsed = fromApi?.toLongOrNull()
when (parsed) {
    null -> println("Не удалось распарсить")
    else -> println("Значение: $parsed")
}

Использование toLong(radix) для систем счисления

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

val hexString = "1A3F"
val decimal = hexString.toLong(16) // основание 16
println(decimal) // 6719

// Безопасная версия с радиксом:
val safeHex = "XYZ".toLongOrNull(16)
println(safeHex) // null

Рекомендуемый паттерн для реального кода

В production-коде лучше всего комбинировать toLongOrNull() с обработкой через let или run:

fun parseUserInput(input: String?): Long {
    return input?.toLongOrNull()?.let { validLong ->
        println("Парсинг успешен: $validLong")
        validLong
    } ?: run {
        println("Ввод некорректен, возвращаем значение по умолчанию")
        0L
    }
}

// Примеры использования
println(parseUserInput("123"))    // Парсинг успешен: 123
println(parseUserInput("abc"))    // Ввод некорректен, возвращаем значение по умолчанию
println(parseUserInput(null))     // Ввод некорректен, возвращаем значение по умолчанию

Сравнение с Java

  • Java: Long.parseLong(str) — исключение; Long.valueOf(str) — исключение; try-catch обязателен.
  • Kotlin: str.toLongOrNull() — возвращает null; элегантно, безопасно, без исключений.

Используйте toLongOrNull() как основной инструмент. Он делает код чище, безопаснее и соответствует философии Kotlin — избегать исключений там, где это возможно.

<<>>

Альтернативный подход: использование try-catch с функцией расширения

Хотя toLongOrNull() — предпочтительный вариант, иногда нужно сохранить информацию об ошибке. Например, для логирования или отображения пользователю конкретного сообщения. В таких случаях можно создать свою функцию-расширение:

fun String?.toLongSafe(): Result {
    return try {
        if (this == null) {
            Result.failure(IllegalArgumentException("Строка равна null"))
        } else {
            Result.success(this.toLong())
        }
    } catch (e: NumberFormatException) {
        Result.failure(e)
    }
}

// Использование
val input = "abc"
val result = input.toLongSafe()
result.fold(
    onSuccess = { value -> println("Успех: $value") },
    onFailure = { error -> println("Ошибка: ${error.message}") }
)

Дополнительно: преобразование с учётом локали

Если строка содержит разделители тысяч (например, "1 000 000" или "1,000,000"), ни toLong(), ни toLongOrNull() не сработают. В этом случае нужно предварительно очистить строку:

fun String.removeSeparators(): String {
    return this.replace(" ", "").replace(",", "").replace(".", "")
}

val formatted = "1 234 567 890"
val cleaned = formatted.removeSeparators()
val longValue = cleaned.toLongOrNull()
println(longValue) // 1234567890

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