en dataklass är ett koncept som inte är knutet till något specifikt programmeringsspråk, det är ett mönster som är tillräckligt bekvämt för de flesta programmerare som ett enkelt sätt att representera, inkapsla och flytta information runt.

en dataklass avser en klass som endast innehåller fält och crud-metoder för åtkomst till dem (getters och setters). Dessa är helt enkelt behållare för data som används av andra klasser. Dessa klasser innehåller ingen ytterligare funktionalitet och kan inte självständigt fungera på de data som de äger.

vanligtvis representerar dataklasser verkliga enheter, och det är vanligt att ha dussintals eller hundratals av dessa klasser i ett projekt, vilket innebär att skapa, modifiera och manipulera dessa objekt det är en mycket vanlig uppgift för en utvecklare.

en dataklass i Java

så här ser en dataklass vanligtvis ut i Java:

du kommer att märka att vi åsidosätter toString() , equals() och hashCode() metoder (deklarerade i klassen Object.java). Varför är åsidosättande av dessa metoder relevanta i dataklasser?

när vi implementerar dessa tre metoder skapar vi värdeobjekt, klasser för vilka två instanser med lämpligt lika fältvärden anses utbytbara. För att vara helt sant måste vi göra klassen oföränderlig. Att göra fälten slutliga och ta bort setters hjälper. Oföränderlighet anses ofta vara en bra praxis och rekommenderas när det är möjligt)

  • equals() : som standard returnerar true bara om de två variablerna hänvisar till samma objekt, dvs om positionen i minnet är densamma. Vi åsidosätter denna metod för att returnera true om objekten innehåller samma information, med andra ord om objekten representerar samma enhet. Det kontrollerar egenskaperna är desamma och de innehåller samma värde.
  • hashCode() : som standard returnerar objektets minnesadress i hexadecimal. Det är ett numeriskt värde att identifiera ett objekt under jämställdhetstestning, dvs lika objekt har samma hashkod. Denna metod måste åsidosättas när toString() åsidosätts så att den returnerar en hashkod beräknad utifrån värdena för egenskaperna.
  • toString(): Som standard returnerar objekttypen och hashCode(), till exempel [email protected]+ . Vi åsidosätter denna metod för att ha en mer läsbar version av objektet som User(name=Steve, surname=Jobs) .

trots att det är ett så viktigt koncept finns det inget i Java-koden ovan som gör denna klass annorlunda än någon annan. Programmerare kan känna igen det som en dataklass på grund av klassstrukturen och mönstren, men ur kompilatorns synvinkel är denna klass bara en annan klass.

att skapa dataklasser är så vanligt att utvecklare ofta använder IDE och andra plugins för att hjälpa dem med denna repetitiva uppgift. Smärtan med att skapa en dataklass i Java kan lindras av plugins eller IDE, men de flesta buggar introduceras på ytterligare modifieringar av dessa klasser. Det är väldigt lätt att glömma att ändra alla följeslagare i enlighet med detta varje gång ett fält tas bort eller läggs till.

en dataklass i Java saknar språkstöd. Det är en repetitiv och buggbenägen uppgift som representerar för mycket friktion för ett modernt programmeringsspråk.

en dataklass i Kotlin

samma dataklass i Kotlin skulle se ut så här:

data class User(var name: String, var age: Int)

Kotlin höjer dataklasser till förstklassiga medborgare som introducerar nyckelordet data. Låt oss bryta ner det.

  • Getters och setters

getters och setters skapas automatiskt i Kotlin när vi deklarerar egenskaper. Kort sagt, vad var name: String betyder är att klassen User har en egenskap som är offentlig (standardsynlighet i Kotlin), mutable (var) och är en String typ. Med tanke på att det är offentligt skapar det getter, och med tanke på att det är muterbart skapar det setter.

om vi vill göra klassen skrivskyddad (inga setters) måste vi använda val :

data class User(val name: String, val age: Int)

vi kan blanda val och var i samma klassdeklaration. Du kan tänka på val som en final variabel i Java.

allt förklaras hittills, det är vanligt att någon klassdeklaration i Kotlin, men data nyckelordet är vad som gör skillnad här.

  • data nyckelordet

att förklara en klass som en dataklass kommer att få oss implementerade toString(), hashCode() och equals() automatiskt på samma sätt som vi beskrivit ovan för Java-klassen. Så om vi skapar en användarklass som User("Steve Jobs",56) och kallar metoden toString() får vi något som:User(name=Steve Jobs, age=56).

Destructuring declarations

nyckelordet data innehåller funktioner som tillåter destructuring declarations. Kort sagt, det skapar en funktion för varje fastighet så att vi kan göra saker som detta:

kopieringsfunktion

nyckelordet data ger oss ett praktiskt sätt att kopiera klasser som ändrar värdet på vissa egenskaper. Om vi vill skapa en kopia av en användare som ändrar åldern är det så vi skulle göra det:

egenskaper som deklareras i klasskroppen ignoreras

kompilatorn använder bara de egenskaper som definierats i den primära konstruktören för de automatiskt genererade funktionerna.

egenskapen address det kommer inte att behandlas med nyckelordet data, så det betyder att de automatiskt genererade implementeringarna kommer att ignorera det.

Par och trippel

Pair och Triple är standarddata klasser i biblioteket, men Kotin docs själva avskräcka användningen av dem till förmån för mer läsbara och skräddarsydda dataklasser.

krav och begränsningar

  • en dataklasskonstruktör måste ha minst en parameter.
  • alla parametrar måste vara marknad som val eller var.
  • en dataklass kan inte vara abstract, open, sealed eller inner.
  • equals , toString och hashCode metoder kan uttryckligen åsidosättas.
  • explicita implementeringar för componentN() och copy() funktioner är inte tillåtna.
  • härleda en dataklass från en typ med en copy() funktionsmatchande signatur avlägsnades i Kotlin 1.2 och förbjöds i Kotlin 1.3.
  • a data klass kan inte sträcka sig från en annan data klass.
  • a data klass kan förlänga andra klasser (sedan Kotlin 1.1)

dataklasser är förstklassiga medborgare i Kotlin. I en mycket kort syntax erbjuder de en friktionslös lösning med alla fördelar och inga kompromisser.

vad betyder det för Android

jag ska försöka förklara vilka är de viktigaste fördelarna som jag har hittat med Kotlin dataklasser i Mina Android-projekt. Dessa är inte alla av dem och kanske inte de viktigaste, men dessa är de mest uppenbara från min erfarenhet hittills.

  • datamodeller

arkitektur i Android var (och är fortfarande) ett hett ämne. Det finns flera alternativ, men de flesta av dem har gemensamt separering av oro och principer för enskilt ansvar. Ren Arkitektur – mycket känd i Android-communityn-är en uppsättning goda metoder att följa när man strävar efter en bra arkitektur som lägger tonvikt på att använda olika modeller för olika lager av arkitekturen. Detta innebär att ett projekt med 3 eller 4 olika datamodeller blir standard.

vad det betyder är att antalet dataklasser i ett projekt är mycket högt och operationer som skapa, läsa, ändra, kopiera, jämföra, kartlägga… datamodellklasser är dagliga uppgifter som drar nytta av Kotin-Dataklassen automatiskt genererad kod. Sparar mycket tid och minskar möjligheterna att introducera buggar.

  • inget mer Auto-värde

att använda värdetyper är en bra praxis som är mycket utökad i Android, särskilt bland dataklasser.

en värdetyp är ett objekt från en oföränderlig värdeklass.
en värdeklass är en klass för vilken jämlikhet beror på dess innehåll.
en oföränderlig klass är en klass som inte kan ändras efter skapandet.

AutoValue är ett populärt bibliotek från Google som hjälper oss att skapa värdetyper. Det gör sitt jobb men det är väldigt verbose för något som inte borde vara så komplicerat.

använda Kotlin data klasser med val access modifier ger oss en tillräckligt nära approximation till värdetyper.

data class User(val name : String, val age : Int)

den tidigare Användarklassen är en klass som är tillräckligt nära för att värdera typer, i en mycket kortare syntax. För en bra bit av människor kan AutoValue ersättas av Kotlin. Mindre kod, ingen annoteringsbehandling och ett mindre bibliotek att vara beroende av.

Obs: Kotlin erbjuder skrivskyddade egenskaper och klasser med nyckelordet val. Skrivskyddad och oföränderlig är inte densamma (mer här) men i allmänhet anses vara tillräckligt bra för praktiska ändamål.

  • inga fler Lombok

ett av de sätt som utvecklare försökte spara tid när det handlar om dataklasser använder bibliotek för att generera getter och setter metoder. Lombok är en av de (i)kända i Android/Java. Det kräver inte bara biblioteket utan också ett plugin för AS. Den långa historien kort är för de flesta utvecklare Lombok få så många fördelar som huvudvärk, så det blir att biblioteket du börjar älska men efter ett tag, du kan inte vänta med att bli av med, men du aldrig göra eftersom är överallt.

med tanke på att Kotlin dataklasser inte kräver att manuellt skriva getter/setter metoder, är det huvudsakliga behovet av Lombok borta.

  • RecyclerView DiffUtil

RecyclerView i Android är widgeten. Det finns i varje app på flera skärmar. En viktig komponent vid implementering av RecyclerView-adaptrar är DiffUtil-klassen. DiffUtil beräknar skillnaden mellan två listor för att skicka ändringarna-om några – till adaptern. Det är mycket effektivare än att uppdatera hela listan om och om igen, och det animerar förändringarna vackert.

DiffUtil är starkt beroende av objektens jämlikhet, vilket betyder att två objekt är desamma när innehållet är detsamma. Varje gång du använder en RecyclerView bör du använda DiffUtil, vilket innebär att du behöver ett sätt att jämföra om två objekt innehåller samma information. Detta är en av anledningarna till att vi måste åsidosätta equals i våra Java – dataklasser, men med Kotlin data – klasser kommer det gratis.

Obs: Om du inte är bekant med DiffUtil kontrollera denna snabbstartsguide.

  • tester

i testklasser kontrollerar vi ständigt om de förväntade värdena matchar de faktiska värdena. Att jämföra objekt jämlikhet (som beskrivits tidigare) är en mycket vanlig uppgift.

även om du inte behöver åsidosätta equals , toString och toHash triplet för din vanliga app runtime, är chansen att du kommer att behöva åsidosätta dessa metoder för teständamål hög, så Kotlin dataklasser rensar vägen till testning utan ursäkter.

tillägg

låt oss prata om några andra vanliga scenarier som är värda att nämna när vi arbetar med Kotlin-dataklasser. Detta är inte strikt relaterat till dataklasser, men är särskilt vanligt bland dem.

  • flera konstruktörer
data class User(val name : String, val age : Int)

i klassen User som vi definierade tidigare måste vi uttryckligen ange name och age när vi skapar en instans som User("Steve", 56).

i Kotlin kan vi definiera standardvärden för argument på ett sådant sätt att om vi inte skickar ett värde för det argumentet tilldelas standardvärdet det.

data class User(val name : String, val age :Int = 0)

User("Steve", 56) är fortfarande giltigt, men nu är en andra konstruktör User("Steve") tillåten. I så fall kommer värdet age att vara 0.

vi kan tilldela standardvärden till båda parametrarna så att en tredje konstruktör User() där name kommer att vara tom och age kommer att vara 0.

data class User(val name : String = "", val age : Int = 0)

så nu User() , User("Steve") och User("Steve",56) alla är giltiga samtal.

detta har vissa begränsningar: valfria parametrar måste vara sista parametrar i konstruktören. Nästa kommer inte att kompilera.

data class User(val name : String = "", val age : Int)
val user = User(56) // This doesn't compile

en annan begränsning är att om vi har flera valfria parametrar måste de hoppas över från höger till vänster.

data class User(
val name : String,
val surname : String = "",
val age : Int = 0
)User("Steve")
User("Steve", "Jobs")
User("Steve", "Jobs", 56)
User("Steve",56) // This wont compile

för att hantera dessa begränsningar erbjuder Kotlin namngivna argument. Detta gör att vi kan ange vilket argument som tillhör varje värde. Nu kan vi göra saker somUser(name = "Steve", age = 56) — eller kortare User("Steve", age = 56) — där efternamnet kommer att tilldelas standardvärdet.

standardargument och namngivna argument är ett mycket praktiskt sätt att erbjuda flera konstruktörer och överbelastningar från en mycket kompakt deklaration.

  • @JvmOverloads

allt som förklaras i föregående punkt tar inte hänsyn till samtal från Java-sidan. Kotlin är interoperabel med Java så vi måste kunna skapa instanser av klassen User från Java.

om du inte kommer att använda den från Java är du klar, men annars behöver du @JvmOverloads – anteckningen med tanke på att Java inte erbjuder namngivna argument.

data class User @JvmOverloads constructor(
val name : String,
val surname : String = "",
val age : Int = 0
)

vad detta gör genererar flera konstruktörer så det kan kallas från Java.

notera: det är viktigt att märka att det inte kommer att skapa alla möjliga permutationer utan de som härrör från att ta bort de valfria argumenten från höger till vänster. Mer här

  • byggare

med tanke på Kotlin erbjuder namngivna parametrar och standardargument, det gör det mindre sannolikt behovet av byggare. Dessutom visar moderna IDEs som Android Studio redan namnet på parametern på samtalssidan vilket gör det lättare att läsa vilket gör det mindre intressant bara för läsbarhetsändamål.

i de fall där byggmönstret fortfarande behövs. Kotlin erbjuder inte något speciellt för att hjälpa oss med det. Ett byggmönster i Kotlin ser ut som:

  • anteckningar

det är mycket vanligt att vissa datamodellklasser använder annoteringsbehandling. Till exempel API-modeller (dataklasser för att representera deserialiserade svar från API) kommenteras ofta med Gson-eller Moshi-anteckningar. Persistensmodellerna (dataklasser för att representera data lagrade i lokal lagring/databaser) kommenteras ofta med rums-eller Realm-anteckningar.

i Kotlin kan vi fortfarande använda dessa anteckningar. Det här är till exempel en användarmodell som ska lagras i Rumsdatabasen:

sammanfattning

Kotlin dataklasser är resultatet av år av lärande från smärta och frustration med dataklasser i Java. De strävar efter att ha alla fördelar och ingen av nackdelarna. Att använda dem är väldigt enkelt och roligt och när du väl är van vid det är det väldigt svårt att se tillbaka.

i Android hjälper de oss på olika sätt, men mestadels sparar de mycket tid och minskar buggar.

en Kotlin – dataklass är ett bra exempel på vad Kotlin är som programmeringsspråk: koncis, pragmatisk och en glädje för utvecklare.

Lämna ett svar

Din e-postadress kommer inte publiceras.

lg