Kotlin Data Class - mariamaged/Java-Android-Kotlin GitHub Wiki
Kotlin - Data Class
One of the reasons why Kotlin has taken off in popularity - particularly for Android app development - is that Java can be tedious to write.
- One way that developers have tried to reduce that tedium is through
annotation processors
that generate Java code for you. - A class example of that is Google's AutoValue.
- AutoValue is for
immutable objects
, ones whose fields havegetters
butno setters
. - In particular, AutoValue can code-generate things like an
equals()
methods that takes all of the fields into account.
- AutoValue is for
How You Declare It
- All you do is add the data keyword to the class declaration.
- The class needs to have 1+ parameters in its constructor.
- Those parameters need to be declared as val or var.
- And typically you will use val.
- That's pretty much it.
- You are welcome to have whatever functions you need on the class, but nothing else is required.
data class Animal(val species: String, val ageInYeards: Float)
What You Gain?
Standard Java Methods
- Kotlin will automatically supply implementation of:
equals()
, which compares each of the properties to see if they are equal.hashCode()
, which generates an Int to be used in place like HashSet and HashMap.toString()
, mostly for debugging purposes, showing the values of each of the properties.
- For Kotlin/JVM, these methods are the standard Java Object methods that ideally get overriden on most classes...yet you do not, because we skip them if we think that we do not need them.
- This is a subset of the Java equivalent of the
Animal
data class shown above:
public final class Animal {
@NotNull
private final String species;
private final float ageInYears;
@NotNull
public final String getSpecies() {
return this.species;
}
public final float getAgeInYears() {
return this.ageInYears;
}
public Animal(@NotNull String species, float ageInYears) {
this.species = species;
this.ageInYears = ageInYears;
}
public String toString() {
return "Animal(species=" + this.species + ", ageInYears=" + this.ageInyears +")";
}
public int hashCode() {
return (this.species != null ? this.species.hashCode() : 0)* 31 + Float.floatToIntBits(this.ageInYears);
}
public boolean equals(Object var1) {
if(this != var1) {
if(var1 instanceof Animal) {
Animal var2 = (Animal) var1;
if(this.species.equals(var2.species) && Float.compare(this.ageInYears), var2.ageInYears) == 0) return true;
}
return false;
}
else return true;
}
}
- Note 1: If you implement these methods yourself in your data class, Kotlin will assume that you know what you are doing.
- Note 2: If your data class extends from other class, Kotlin will skip any of those functions that the class implements and marks as final.
copy()
Kotlin also generates a
copy()
function.
- As the name suggests, this creates a copy of an instance of your data class.
- However, what the function really does is:
- Accept all of the properties as function parameters.
- Defaulted to the current values from the instance.
- This allows you to
selectively override values
in the copy, which is a great place to usenamed parameters
. - So, out second Animal copied the species but has a different
ageInYears
, courtesy of the value we provided tocopy()
.
data class Animal(val species: String, val ageInYears: Float)
val critter = Animal("frog", 3.14F)
val youngerCriter = critter.copy(ageInYears = 0.1F)
println(youngerCritter) // Prints Animal(species=frog, ageInYears=0.1)
What You Lose
- You cannot subclasses of data classes.
- A data class cannot be marked with open to allow it to be extended.
- If subclasses were allowed, it is possible that subclasses would change the class definitions in ways that might make the code-generated
equals()
and other methods be invalid.
- A side effect of the no-subclasses limitation is that data classes cannot be abstract.
Data Classes With Other Properties
- You are welcome to have other properties in your data classes, beyond those in the constructor.
- However, code generated functions, like
equals()
andcopy()
will ignore these properties. - Those functions only incorporate the properties defined in the primary constructor.
- Sometimes,
This can be a feature:
you might want some properties to be ignore forequals()
andhashCode()
.This can be a bug:
you might not realize thatcopy()
only copies a subset of your properties.
data class Animal(val species: String, val ageInYears: Float) {
var is Friendly = true
var isHungry = true
val is CommonlySeenFlyingInTornados = false
}