Как преобразовать строку (String) в число (Long) в Kotlin? Безопасные способы и обработка ошибок
Основные способы преобразования String в Long
Вы абсолютно правы: прямое использование .toLong() без проверки — это путь к NumberFormatException. Kotlin предлагает гораздо более элегантные и безопасные альтернативы. Давайте разберем их по порядку.
1. Стандартный метод .toLong() (с обработкой исключений)
Это прямой аналог Java-метода Long.parseLong(). Он выбрасывает исключение, если строка не является валидным числом:
fun main() {
val validInput = "12345"
val invalidInput = "12abc"
val nullInput: String? = null
// Работает
val number1: Long = validInput.toLong()
println(number1) // 12345
// Падает с NumberFormatException
// val number2 = invalidInput.toLong()
// Падает с NullPointerException (если строка nullable)
// val number3 = nullInput!!.toLong()
}
Когда использовать: только если вы на 100% уверены в корректности строки и готовы ловить исключения через try-catch.
2. Безопасный метод .toLongOrNull() (рекомендуемый)
Это лучший способ для большинства случаев. Метод возвращает Long? (nullable Long): если строка валидна — число, иначе — null. Никаких исключений!
fun main() {
val userInput = "123abc"
val userId: Long? = userInput.toLongOrNull()
// Безопасная обработка
val result = userId ?: -1L // значение по умолчанию
println("User ID: $result") // User ID: -1
// Или через when
when (userId) {
null -> println("Ошибка ввода!")
else -> println("ID = $userId")
}
}
Важно: этот метод также обрабатывает пробелы? Да, но только если строка состоит из цифр и, опционально, знака минус в начале. Пробелы в начале/конце НЕ обрезаются автоматически.
3. Комбинация .trim().toLongOrNull() (для пользовательского ввода)
Если вы работаете с вводом от пользователя (например, из EditText или консоли), всегда удаляйте лишние пробелы:
fun parseUserInput(input: String?): Long? {
return input
?.trim() // удаляем пробелы, если строка не null
?.toLongOrNull() // конвертируем или возвращаем null
}
fun main() {
println(parseUserInput(" 42 ")) // 42
println(parseUserInput("")) // null
println(parseUserInput(" ")) // null (пустая после trim)
println(parseUserInput(null)) // null
println(parseUserInput("3.14")) // null (не Long)
}
4. Расширение String?.toLongOrDefault(default)
Если вам часто нужно значение по умолчанию, можно написать свой extension:
fun String?.toLongOrDefault(default: Long = 0L): Long {
return this?.trim()?.toLongOrNull() ?: default
}
fun main() {
println("456".toLongOrDefault()) // 456
println("abc".toLongOrDefault(-1L)) // -1
println(null.toLongOrDefault(42L)) // 42
}
5. Использование toLong(radix) для других систем счисления
Kotlin поддерживает конвертацию из строк в разных системах счисления (radix = 2..36):
fun main() {
val binaryString = "1010"
val hexString = "FF"
println(binaryString.toLong(2)) // 10 (двоичная)
println(hexString.toLong(16)) // 255 (шестнадцатеричная)
// Безопасные версии тоже есть:
println(binaryString.toLongOrNull(2)) // 10
println("GG".toLongOrNull(16)) // null
}
Резюме: какой метод выбрать?
- Для надежного production-кода: используйте
.trim().toLongOrNull()+ оператор Элвиса (?:) для значения по умолчанию. - Если нужен null при ошибке:
.toLongOrNull()(с предварительным trim при необходимости). - Если строка гарантированно корректна:
.toLong(), но лучше всё равно перестраховаться. - Для nullable строк: всегда используйте безопасный вызов
?.toLongOrNull().
Главное преимущество Kotlin перед Java в этом вопросе — вы можете избежать исключений вообще, работая через nullable типы и функции с суффиксом OrNull. Это делает код чище и безопаснее.
Альтернативный подход: использование NumberFormatException в стиле Kotlin
Хотя toLongOrNull() — предпочтительный способ, иногда вам может понадобиться явно обработать исключение, например, чтобы залогировать ошибку или показать пользователю сообщение. В Kotlin это делается лаконично через runCatching:
fun parseWithLogging(input: String): Long? {
return runCatching {
input.trim().toLong()
}.onFailure { exception ->
// Логируем ошибку
println("Не удалось распарсить '$input': ${exception.message}")
}.getOrNull()
}
fun main() {
println(parseWithLogging("100")) // 100
println(parseWithLogging("abc")) // null (с логом в консоли)
}
runCatching — это обертка над try-catch, которая возвращает Result. Вы можете использовать .getOrDefault() или .getOrThrow() для гибкой обработки.
Дополнительный совет: если вы парсите большие объемы данных (например, из CSV-файла) и производительность критична, используйте java.lang.Long.parseLong() напрямую — он работает чуть быстрее, чем Kotlin-аналоги. Но для 99% приложений разница незаметна.
Также помните, что Kotlin поддерживает символ подчеркивания в числах для читаемости: "1_000_000".toLong() вернет 1000000.