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

Почему val лучше чем var?

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

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

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

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

Почему val лучше чем var в Kotlin

Это классический Kotlin вопрос, который раскрывает понимание функционального программирования и лучших практик. Давай разберёмся почему val имеет приоритет.

Основная разница

val — immutable переменная (читай как value), после присвоения нельзя переприсвоить

var — mutable переменная (читай как variable), можно менять значение сколько угодно

// val — immutable
val name = "John"
name = "Jane"  // Ошибка компиляции!

// var — mutable
var age = 25
age = 26  // OK

Почему val лучше

1. Меньше bugs — меньше изменяемого состояния

// Плохо — var создаёт неопределённость
var user: User? = fetchUser()
if (user != null) {
    // Где-то в коде user может быть переприсвоен
    // На какого пользователя мы сейчас смотрим?
    renderUser(user)
}

// Хорошо — val гарантирует стабильность
val user: User? = fetchUser()
if (user != null) {
    // user не изменится в этом блоке
    renderUser(user)
}

2. Easier reasoning about code

Когда видишь val, знаешь что его значение не изменится. Это делает code mental model проще:

// Плохо
var result = calculateSomething()  // Что дальше произойдёт с result?
result = calculateSomethingElse(result)  // Переприсвоили!
result = processResult(result)  // И ещё раз!
return result  // Какой это result?

// Хорошо — ясно что каждый шаг это новое вычисление
val calculation1 = calculateSomething()
val calculation2 = calculateSomethingElse(calculation1)
val result = processResult(calculation2)
return result

3. Thread safety — нет race conditions

// Плохо — может быть data race в многопоточности
var counter = 0
launch(Dispatchers.Default) {
    counter++  // Thread 1
}
launch(Dispatchers.Default) {
    counter++  // Thread 2
}
// Результат непредсказуем!

// Хорошо — immutable, никаких race conditions
val immutableCounter = AtomicInteger(0)
launch(Dispatchers.Default) {
    immutableCounter.incrementAndGet()
}
launch(Dispatchers.Default) {
    immutableCounter.incrementAndGet()
}

4. Лучше для тестирования

// Плохо — var может быть изменён в тесте
class UserRepository {
    var cache: Map<Int, User> = emptyMap()  // Кто-то может изменить в тесте
}

// Хорошо — val гарантирует неизменяемость
class UserRepository {
    val cache: Map<Int, User> = emptyMap()  // Стабильно для тестов
}

5. Функциональное программирование — основа Kotlin

Kotlin следует парадигме функционального программирования где immutability это основной принцип:

// Функциональный стиль — используем val и pure функции
data class User(val id: Int, val name: String)

fun updateUser(user: User, newName: String): User {
    return user.copy(name = newName)  // Новый объект, не мутируем старый
}

val user1 = User(1, "John")
val user2 = updateUser(user1, "Jane")  // user1 не изменился

6. Компилятор может оптимизировать

Если переменная val (immutable), компилятор может:

  • Inline значение где это оптимально
  • Удалить ненужные копирования
  • Лучше optimизировать bytecode
// val позволяет компилятору оптимизировать
val fixedValue = 100
repeat(1000000) {
    println(fixedValue)  // Компилятор знает что это всегда 100
}

// var требует проверки каждый раз
var mutableValue = 100
repeat(1000000) {
    println(mutableValue)  // Может быть изменён?
}

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

По умолчанию используй val, var только если действительно нужна мутация

Это как правило clean code:

// Правило: начни с val
val name = "John"  // Нужно ли менять? Нет
val age = 25       // Нужно ли менять? Нет
val balance = 1000.0  // Нужно ли менять? Нет

// Редко когда нужен var
var retryCount = 0  // Нужно ли менять? Да, в loop
while (retryCount < 3) {
    try {
        makeNetworkCall()
        break
    } catch (e: Exception) {
        retryCount++  // Увеличиваем счётчик
    }
}

Важное уточнение: val и mutability

Важно: val делает переменную immutable, но не объект который она ссылается!

// val переменная, но список мутируемый
val list = mutableListOf(1, 2, 3)
list.add(4)  // OK! Список изменился
// list = emptyList()  // Ошибка! Переменную нельзя переприсвоить

// Если нужен immutable список
val immutableList: List<Int> = listOf(1, 2, 3)
// immutableList.add(4)  // Ошибка компиляции!

Best practice в Android

Используй val везде где возможно:

// Activity
class MainActivity : AppCompatActivity() {
    private val binding: ActivityMainBinding by lazy {  // val!
        ActivityMainBinding.inflate(layoutInflater)
    }
    
    private val viewModel: MainViewModel by viewModels()  // val!
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // val для всех переменных что не меняются
        val user = intent.getParcelableExtra<User>("user")
        val isAdmin = user?.role == "admin"
        
        renderUI(user, isAdmin)
    }
}

// ViewModel
class MainViewModel : ViewModel() {
    private val _user = MutableLiveData<User>()  // Иногда нужен var для инициализации
    val user: LiveData<User> = _user  // Но публичный — val
    
    fun loadUser(id: Int) {
        viewModelScope.launch {
            val userData = repository.getUser(id)  // val!
            _user.value = userData
        }
    }
}

// Repository
class UserRepository {
    private val database: AppDatabase by lazy {  // val!
        Room.databaseBuilder(context, AppDatabase::class.java, "db").build()
    }
    
    suspend fun getUser(id: Int): User {
        return database.userDao().getById(id)  // val в функции
    }
}

Когда использовать var

// 1. Loop counter
var count = 0
for (item in items) {
    count++
}

// 2. Mutable state что должно меняться
class Game {
    var score = 0  // Игра постоянно обновляет score
    var health = 100  // Здоровье персонажа меняется
}

// 3. Late initialization (но лучше использовать lazy или lateinit)
var initialized = false
setupData()  // Инициализируем
initialized = true

// Лучше
val initialized: Boolean by lazy {
    setupData()
    true
}

Выводы

  1. val по умолчанию — используй везде где возможно
  2. var только если нужна мутация — будь осторожен с изменяемым состоянием
  3. val делает код безопаснее — меньше bugs
  4. val улучшает readability — ясно что не изменится
  5. val помогает многопоточности — нет race conditions
  6. Kotlin style — функциональное программирование предпочитает immutability

Это один из главных принципов Kotlin дизайна — безопасность и readability через immutability.

Почему val лучше чем var? | PrepBro