You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin数据类字段声明最佳实践:参数选var/val?是否加private?

Great question—this is a common point of confusion with Kotlin data classes, especially when you need to add custom logic like your non-negative amount check. Let's break down the best practices step by step:

1. Always prefer val for data class parameters (when possible)

Data classes are built for value objects—things like Money, DateRange, or ProductId where the instance's meaning is tied directly to its data. Using val makes these instances immutable, which is a huge win for:

  • Thread safety: No race conditions from concurrent modifications.
  • Predictability: Once created, the instance's state never changes, so auto-generated methods like equals(), hashCode(), and toString() will always behave consistently.
  • Safer code: You don't have to worry about accidental state changes breaking logic (like a Money instance suddenly having a negative value elsewhere in your app).

In your case, currency is already a val (perfect!), and your amount validation logic doesn't require mutability—we'll fix that in a second.

2. When to use var in a data class?

Only reach for var if you absolutely need the property to be changeable after the instance is created. But be cautious: mutable data classes can violate value semantics. For example, if you store a mutable Money instance in a HashMap, modifying its amount later would break the map's ability to find it (since hashCode() would change).

If you must have mutability (e.g., a stateful entity that needs updates), var is allowed—but ask yourself if a regular class (not a data class) might be a better fit, since data classes are optimized for immutable values.

3. When to add private to data class parameters?

Add private when you want to hide the parameter from the class's public API. By default, any val/var in a data class's primary constructor becomes a public property that external code can access directly.

Your use of _amount as a backing field for validation is exactly the right scenario for private—you don't want external code to bypass your non-negative check and access the raw, potentially negative value.

4. Optimizing your Money class for best practices

Your current code uses var for both _amount and amount, but you don't actually need mutability here. You can rewrite it with all vals to follow value object best practices:

data class Money(private val _amount: Int, private val currency: String) {
    val amount: Int
        get() = if (_amount < 0) 0 else _amount

    override fun toString(): String {
        return "Money(amount=$amount, currency='$currency')"
    }
}

This works because:

  • _amount is a private val—set once in the constructor, never modified, and hidden from external code.
  • The public amount property is a val with a custom getter that applies your non-negative logic. Since it doesn't need its own backing field, there's no reason to use var.
  • You still get all data class perks: auto-generated equals()/hashCode() based on _amount and currency, a working copy() method, etc.

Quick Best Practice Cheat Sheet

  • Default to val: Enforce immutability for data classes whenever possible.
  • Use var sparingly: Only for mutable state, and consider a regular class instead.
  • Add private for internal details: Hide backing fields or implementation-specific parameters from the public API.
  • Custom getters don't need var: Use val with a custom getter if you're transforming a value, not modifying it.

内容的提问来源于stack exchange,提问作者VolodymyrH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:55:02