← Назад к вопросам

Объясните разницу между val и var в Kotlin. Что такое nullable и non-nullable типы?

1.2 Junior🔥 221 комментариев
#Kotlin основы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

val vs var и Nullable vs Non-Nullable типы

val vs var

val — неизменяемая переменная (read-only), immutable

val name = "John"
name = "Jane"  // Ошибка! Val cannot be reassigned

var — изменяемая переменная, mutable

var age = 25
age = 26  // OK! Можно переиспользовать

Разница:

valvar
Нельзя переиспользоватьМожно переиспользовать
ПотокобезопаснееТребует синхронизации
Предпочтителен по умолчаниюИспользуется реже
ПроизводительнееЧуть медленнее

Примеры

// val — используй для константных данных
val pi = 3.14
val isActive = true
val users = listOf("John", "Jane")

// var — используй для изменяющегося состояния
var counter = 0
var isLoading = false
var currentUser: User? = null

Nullable типы (может быть null)

Тип с ? означает, что переменная может содержать null:

val name: String? = null  // OK
val age: Int? = null       // OK

val city: String? = "Moscow"
println(city)              // Moscow

val country: String? = null
println(country)           // null

Non-nullable типы (НЕ может быть null)

Тип БЕЗ ? означает, что переменная ВСЕГДА имеет значение:

val name: String = "John"  // OK
val age: Int = 25          // OK

val city: String = null    // Ошибка! Type mismatch

val country: String = "Russia"  // OK

Null Safety в Kotlin

Проблема в Java:

String name = getNullableString();
int length = name.length();  // NullPointerException!

Решение в Kotlin:

val name: String? = getNullableString()
val length = name?.length  // Safe call, может быть null

Работа с Nullable типами

1. Safe Call Operator (?.):

val user: User? = getUser()
val name = user?.name  // name: String? (может быть null)
println(name)  // null или значение

2. Elvis Operator (?:):

val userName = user?.name ?: "Guest"
// Если user?.name == null, используй "Guest"

3. Not-null Assertion (!!):

val user: User? = getUser()
val name = user!!.name  // Кидаем NullPointerException если null
// Используй только когда УВЕРЕН в значении!

4. Safe Cast (as?):

val any: Any = "String"
val str = any as? String  // "String"
val num = any as? Int     // null

Пример: обработка null

val user: User? = getUser()

// Плохо — использование !!
val email = user!!.email

// Хорошо — safe call + elvis
val email = user?.email ?: "unknown@example.com"

// Хорошо — let для non-null
user?.let { safeUser ->
    println("Имя: ${safeUser.name}")
    println("Email: ${safeUser.email}")
} ?: run {
    println("User is null")
}

Пример: Collections

val numbers: List<Int> = listOf(1, 2, 3)  // Не может быть null
val nullableList: List<Int>? = null        // Сам список может быть null
val listWithNulls: List<Int?> = listOf(1, null, 3)  // Элементы могут быть null

// Разные типы!
val list1: List<String>     // Non-null список non-null строк
val list2: List<String>?    // Nullable список non-null строк
val list3: List<String?>    // Non-null список nullable строк
val list4: List<String?>?   // Nullable список nullable строк

Пример в ViewModel

class UserViewModel : ViewModel() {
    val userName: String = "John"  // Никогда null
    val userEmail: String? = null  // Может быть null
    
    fun displayUser() {
        // Безопасное обращение
        val email = userEmail ?: "No email"
        println(email)
    }
}

Пример в Coroutine

val result: Result<User>? = null

val user = result?.getOrNull()  // User?
println(user?.name ?: "Unknown")  // Safe handling

// Или
result?.let { safeResult ->
    val user = safeResult.getOrNull()
    println(user?.name)
}

Правила использования

Используй val:

  • По умолчанию для всего
  • Для параметров функций
  • Для properties в data class
  • Для constantes

Используй var:

  • Только если переменная меняется
  • В состояниях UI (remember, mutableState)
  • В счётчиках и флагах

Nullable типы:

  • Когда данные могут отсутствовать
  • Для optional параметров
  • При работе с API
  • Для обработки ошибок

Non-Nullable типы:

  • По умолчанию для всего
  • Для гарантированных данных
  • Для повышения типобезопасности

Вывод

  • val — неизменяемо, var — изменяемо
  • String? — может быть null, String — никогда null
  • Kotlin защищает от null-ошибок на уровне типов
  • Используй safe operators для работы с nullable типами
  • Предпочитай non-nullable типы и val по умолчанию