web-dev-qa-db-fra.com

Comment créer un constructeur vide pour la classe de données dans Kotlin Android

J'ai 10+ paramètres dans une classe de données, je souhaite initialiser la classe de données avec un constructeur vide et définir les valeurs pour quelques paramètres uniquement à l'aide de setter et transmettre l'objet au serveur.

data class Activity(
        var updated_on: String,
        var tags: List<String>,
        var description: String,
        var user_id: List<Int>,
        var status_id: Int,
        var title: String,
        var created_at: String,
        var data: HashMap<*, *>,
        var id: Int,
        var counts: LinkedTreeMap<*, *>,
)

Usage:

Quelque chose comme ça sera facile

                val activity =  Activity();
                activity.title = "New Computer"
                sendToServer(activity)

Mais il faut que tous les arguments soient passés en même temps que le constructeur. Comment puis-je simplifier comme ci-dessus?

                val activity =  Activity(null,null,null,null,null,"New Computer",null,null,null,null);
                sendToServer(activity)
95
Sai Kiran

Vous avez 2 options ici:

  1. Attribuez une valeur par défaut à chaque constructeur primaire paramètre:

    data class Activity(
        var updated_on: String = "",
        var tags: List<String> = emptyList(),
        var description: String = "",
        var user_id: List<Int> = emptyList(),
        var status_id: Int = -1,
        var title: String = "",
        var created_at: String = "",
        var data: HashMap<*, *> = hashMapOf<Any, Any>(),
        var id: Int = -1,
        var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
    ) 
    
  2. Déclarez un constructeur secondaire qui n'a pas de paramètre:

    data class Activity(
        var updated_on: String,
        var tags: List<String>,
        var description: String,
        var user_id: List<Int>,
        var status_id: Int,
        var title: String,
        var created_at: String,
        var data: HashMap<*, *>,
        var id: Int,
        var counts: LinkedTreeMap<*, *>
    ) {
        constructor() : this("", emptyList(), 
                             "", emptyList(), -1, 
                             "", "", hashMapOf<Any, Any>(), 
                             -1, LinkedTreeMap<Any, Any>()
                             )
    }
    

Si vous ne comptez pas sur copy ou equals de la classe Activity ou n'utilisez pas du tout les méthodes data class générées automatiquement, vous pouvez utiliser une classe régulière comme ceci:

class ActivityDto {
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
}

Tous les DTO ne doivent pas nécessairement être un data class et vice versa. En fait, d'après mon expérience, les classes de données sont particulièrement utiles dans les domaines impliquant une logique métier complexe. 

139
miensol

Si vous donnez les valeurs default à tous les champs - le constructeur vide est généré automatiquement par Kotlin.

data class User(var id: Long = -1,
                var uniqueIdentifier: String? = null)

et vous pouvez simplement appeler:

val user = User()

Avec @miensol answer, permettez-moi d'ajouter quelques détails:

Si vous voulez un constructeur vide visible par Java utilisant des classes de données, vous devez le définir explicitement.

L'utilisation de valeurs par défaut + spécificateur de constructeur est assez simple:

data class Activity(
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
) {
    constructor() : this(title = "") // this constructor is an explicit
                                     // "empty" constructor, as seen by Java.
}

Cela signifie qu'avec cette astuce, vous pouvez maintenant sérialiser/désérialiser cet objet avec les sérialiseurs Java standard (Jackson, Gson, etc.).

10
Gui13

Si vous attribuez une valeur par défaut à chaque paramètre de constructeur principal:

data class Item(var id: String = "",
            var title: String = "",
            var condition: String = "",
            var price: String = "",
            var categoryId: String = "",
            var make: String = "",
            var model: String = "",
            var year: String = "",
            var bodyStyle: String = "",
            var detail: String = "",
            var latitude: Double = 0.0,
            var longitude: Double = 0.0,
            var listImages: List<String> = emptyList(),
            var idSeller: String = "")

et de la classe où les instances vous pouvez l'appeler sans arguments ou avec les arguments que vous avez à ce moment

var newItem = Item()

var newItem2 = Item(title = "exampleTitle",
            condition = "exampleCondition",
            price = "examplePrice",
            categoryId = "exampleCategoryId")
1
yOshi

De la documentation

REMARQUE: sur la machine virtuelle Java, si tous les paramètres du constructeur principal ont des valeurs par défaut, le compilateur générera un constructeur supplémentaire sans paramètre qui utilisera les valeurs par défaut. Cela facilite l'utilisation de Kotlin avec des bibliothèques telles que Jackson ou JPA qui créent des instances de classe via des constructeurs sans paramètre.

1
Gastón Saillén

Je suggérerais de modifier le constructeur primaire et d'ajouter un valeur par défaut à chaque paramètre:

data class Activity(
    var updated_on: String = "",
    var tags: List<String> = emptyList(),
    var description: String = "",
    var user_id: List<Int> = emptyList(),
    var status_id: Int = -1,
    var title: String = "",
    var created_at: String = "",
    var data: HashMap<*, *> = hashMapOf<Any, Any>(),
    var id: Int = -1,
    var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
)

Vous pouvez également rendre les valeurs nullables en ajoutant ?, puis vous pouvez assing null:

data class Activity(
    var updated_on: String? = null,
    var tags: List<String>? = null,
    var description: String? = null,
    var user_id: List<Int>? = null,
    var status_id: Int? = null,
    var title: String? = null,
    var created_at: String? = null,
    var data: HashMap<*, *>? = null,
    var id: Int? = null,
    var counts: LinkedTreeMap<*, *>? = null
)

En règle générale, il est recommandé d'éviter les objets pouvant être annulés - écrivez le code de manière à ce qu'il ne soit pas nécessaire de les utiliser. Les objets non nullables sont l’un des avantages de Kotlin par rapport à Java. Par conséquent, la première option ci-dessus est préférable .

Les deux options vous donneront le résultat souhaité:

val activity = Activity()
activity.title = "New Computer"
sendToServer(activity)
0
Micer

Constructeur secondaire non vide pour la classe de données dans Kotlin:

data class ChemicalElement(var name: String,
                           var symbol: String,
                           var atomicNumber: Int,
                           var atomicWeight: Double,
                           var nobleMetal: Boolean?) {

    constructor(): this("Silver",
                        "Ag", 
                        47,
                        107.8682,
                        true)
}

fun main() {
    var chemicalElement = ChemicalElement()
    println("RESULT: ${chemicalElement.symbol} means ${chemicalElement.name}")
    println(chemicalElement)
}

// RESULT: Ag means Silver
// ChemicalElement(name=Silver, symbol=Ag, atomicNumber=47, atomicWeight=107.8682, nobleMetal=true)

Constructeur secondaire vide pour la classe de données dans Kotlin:

data class ChemicalElement(var name: String,
                           var symbol: String,
                           var atomicNumber: Int,
                           var atomicWeight: Double,
                           var nobleMetal: Boolean?) {

    constructor(): this("",
                        "", 
                        -1,
                        0.0,
                        null)
}

fun main() {
    var chemicalElement = ChemicalElement()
    println(chemicalElement)
}

// ChemicalElement(name=, symbol=, atomicNumber=-1, atomicWeight=0.0, nobleMetal=null)
0
ARGeo