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

195

J'ai plus de 10 paramètres dans une classe de données, je veux initialiser la classe de données avec un constructeur vide et définir les valeurs uniquement pour quelques paramètres à 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 cela nécessite que tous les arguments soient passés lors de la création du constructeur. Comment puis-je simplifier comme ci-dessus?

                val activity =  Activity(null,null,null,null,null,"New Computer",null,null,null,null);
                sendToServer(activity)
Sai
la source

Réponses:

246

Vous avez 2 options ici:

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

    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ètres:

    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 copyou equalsde la Activityclasse ou n'utilisez pas du tout les data classméthodes 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 n'ont pas besoin d'être un data classet vice versa. En fait, d'après mon expérience, je trouve que les classes de données sont particulièrement utiles dans les domaines qui impliquent une logique métier complexe.

miensol
la source
1
Merci @miensol, y a-t-il un moyen de le faire en utilisant le plaisir de la copie. par exemple. kotlinlang.org/docs/reference/data-classes.html#copying
Sai
@SaiKiran pour l'utiliser, copyvous avez besoin d'une instance de classe de données. Pour le créer, vous devez appeler un constructeur - et voici le problème.
miensol
J'utilise Kotlin 1.1.2 pour Android Studio 2.3 et emptyList n'est pas disponible: /
Gonzalo
Ça ne fait rien. Je n'ai pas ajouté kotlin à mon fichier de configuration build.gradle.
Gonzalo
3
@Muhammadchhota n'allouera emptyListpas de mémoire à plusieurs reprises. Il renvoie un singleton .
miensol
71

Si vous donnez des valeurs par défaut à tous les champs - un 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()
Kosiara - Bartosz Kosarzycki
la source
1
si l'ID est généré automatiquement, comment l'utiliser?
Siddhpura Amit
A travaillé pour moi. Pour le message Firebase Chat:class FeelComChatMessage (messageText: String = "", messageUser: String = "")
Jitendra Surve
14

En plus de la réponse @miensol, 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 des 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.).

Gui13
la source
Le dernier éloge est faux. Au moins pour le sérialiseur Gson, en fait, Gson utilise le mécanisme unsafe pour créer des objets et il n'appellera pas votre constructeur. Je viens de répondre à une question connexe ici stackoverflow.com/questions/59390294/…
Võ Quang Hòa
6

Si vous donnez une valeur par défaut à chaque paramètre du 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")
yOshi
la source
3

Je suggère de modifier le constructeur principal et d'ajouter une 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 nulles 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 général, il est recommandé d'éviter les objets Nullable - écrivez le code de la manière dont nous n'avons pas besoin 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)
Micer
la source
2

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)
Andy Fedoroff
la source
2

De la documentation

REMARQUE: Sur la JVM, si tous les paramètres du constructeur principal ont des valeurs par défaut, le compilateur générera un constructeur sans paramètre supplémentaire 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.

Gastón Saillén
la source