Introduction and Comparison to JAVA

In JAVA when you want to create a simple POJO class , you have to do a lot of ceremony, write getter/setter for all properties, write equal, toString and hashCode function. While the verbosity of it is good in some cases, writing and maintaining such unnecessarily huge classes is tough. Kotlin introduces Data class to tackle this problem and make the life of developer a little bit more easier.

Prerequisite of this tutorial is that you must have basic understanding of classes in Kotlin.

Below is a simple ‘MovieDetail’ class in JAVA with getters and setters for every field.

public class MovieDetail { private String name; private int rating; private String director; private Date releaseDate; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getRating() { return rating; } public void setRating(int rating) { this.rating = rating; } public String getDirector() { return director; } public void setDirector(String director) { this.director = director; } public Date getReleaseDate() { return releaseDate; } public void setReleaseDate(Date releaseDate) { this.releaseDate = releaseDate; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MovieDetail that = (MovieDetail) o; if (rating != that.rating) return false; if (name != null ? !name.equals(that.name) : that.name != null) return false; if (director != null ? !director.equals(that.director) : that.director != null) return false; return releaseDate != null ? releaseDate.equals(that.releaseDate) : that.releaseDate == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + rating; result = 31 * result + (director != null ? director.hashCode() : 0); result = 31 * result + (releaseDate != null ? releaseDate.hashCode() : 0); return result; } @Override public String toString() { return "MovieDetail{" + "name='" + name + '\'' + ", rating=" + rating + ", director='" + director + '\'' + ", releaseDate=" + releaseDate + '}'; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 public class MovieDetail { private String name ; private int rating ; private String director ; private Date releaseDate ; public String getName ( ) { return name ; } public void setName ( String name ) { this . name = name ; } public int getRating ( ) { return rating ; } public void setRating ( int rating ) { this . rating = rating ; } public String getDirector ( ) { return director ; } public void setDirector ( String director ) { this . director = director ; } public Date getReleaseDate ( ) { return releaseDate ; } public void setReleaseDate ( Date releaseDate ) { this . releaseDate = releaseDate ; } @Override public boolean equals ( Object o ) { if ( this == o ) return true ; if ( o == null || getClass ( ) != o . getClass ( ) ) return false ; MovieDetail that = ( MovieDetail ) o ; if ( rating != that . rating ) return false ; if ( name != null ? ! name . equals ( that . name ) : that . name != null ) return false ; if ( director != null ? ! director . equals ( that . director ) : that . director != null ) return false ; return releaseDate != null ? releaseDate . equals ( that . releaseDate ) : that . releaseDate == null ; } @Override public int hashCode ( ) { int result = name != null ? name . hashCode ( ) : 0 ; result = 31 * result + rating ; result = 31 * result + ( director != null ? director . hashCode ( ) : 0 ) ; result = 31 * result + ( releaseDate != null ? releaseDate . hashCode ( ) : 0 ) ; return result ; } @Override public String toString ( ) { return "MovieDetail{" + "name='" + name + '\'' + ", rating=" + rating + ", director='" + director + '\'' + ", releaseDate=" + releaseDate + '}' ; } }

Data Class Magic!

Now below is the same class in Kotlin using Data class.

data class MovieDetail(val name: String, var rating: Int, val director: String, val releaseDate: Date) 1 2 3 4 data class MovieDetail ( val name : String , var rating : Int , val director : String , val releaseDate : Date )

Unbelievable Right! To create a data class, you have to use the data keyboard and append in front of your class declaration. That is it!

Data class provides you with everything, getters, setters, hashCode, toString and equals functions. So all you have to do is create an instance and start using the functions.

val movie = MovieDetail("Some Random Movie", 7, "Mr. X", Date()) val anotherMovie = MovieDetail("Some Random Movie", 7, "Mr. X", Date()) println(movie.hashCode()) println(movie.toString()) if (movie.equals(anotherMovie)) { println("Movies are same!") } movie.rating = 8 1 2 3 4 5 6 7 8 9 10 11 val movie = MovieDetail ( "Some Random Movie" , 7 , "Mr. X" , Date ( ) ) val anotherMovie = MovieDetail ( "Some Random Movie" , 7 , "Mr. X" , Date ( ) ) println ( movie . hashCode ( ) ) println ( movie . toString ( ) ) if ( movie . equals ( anotherMovie ) ) { println ( "Movies are same!" ) } movie . rating = 8

Components

Components is another way that Kotlin provides to access the class fields. Theses are set of functions with which you can access all the properties in the sequence they are defined. The syntax is very simple, the name “component” followed by the sequence number, componentX(), where X is the sequence number of property you want to access. So for this example:

component1() will return the value stored in variable name .

component2() will return the value stored in variable rating .

component3() will return the value stored in variable director .

component4() will return the value stored in variable releaseDate.

println(movie.component1()) //Will return "Some Random Movie". println(movie.component2()) //Will return 7. println(movie.component3()) //Will return "Mr. X". println(movie.component4()) //Will return the stored date object. 1 2 3 4 println ( movie . component1 ( ) ) //Will return "Some Random Movie". println ( movie . component2 ( ) ) //Will return 7. println ( movie . component3 ( ) ) //Will return "Mr. X". println ( movie . component4 ( ) ) //Will return the stored date object.

If you try to go above the sequence, e.g. component5() then the compiler will throw an error because there is no field with sequence number 5.

Destructuring in loops

In kotlin you can destructure individual objects when iterating over loops, so you wouldn’t need to access the fields by using the object each time (rather than writing movie.name you can directly use name).

var movie1 = MovieDetail("Random 1", 8, "Mr. E", Date()) var movie2 = MovieDetail("Random 2", 7, "Mr. L", Date()) var movie3 = MovieDetail("Random 3", 6, "Mr. Y", Date()) var movie4 = MovieDetail("Random 4", 9, "Mr. A", Date()) val movies = listOf(movie1, movie2, movie3, movie4) for((name, rating, director, date) in movies) { println("${name} was released in ${date}") } 1 2 3 4 5 6 7 8 9 10 var movie1 = MovieDetail ( "Random 1" , 8 , "Mr. E" , Date ( ) ) var movie2 = MovieDetail ( "Random 2" , 7 , "Mr. L" , Date ( ) ) var movie3 = MovieDetail ( "Random 3" , 6 , "Mr. Y" , Date ( ) ) var movie4 = MovieDetail ( "Random 4" , 9 , "Mr. A" , Date ( ) ) val movies = listOf ( movie1 , movie2 , movie3 , movie4 ) for ( ( name , rating , director , date ) in movies ) { println ( "${name} was released in ${date}" ) }

Here you can see, inside the for loop, rather than writing a single name such as movie and then calling movie.name, movie.date, we directly destructured the fields by writing (name, rating, director, date). Remember, the fields can only be accessed in the order in which they were defined. So you cannot access rating before name, you would have to provide a variable for name and then will you be able to provide one for rating.

Read/Write Fields vs Read only Fields

This is not related to just Data classes, but also to normal class and variable definition, but I thought it might be good to cover it here.

When you define a field, you have two options while declaration, val or var. Here is a simple definition for both.

val (Read Only) – When you define a field using val, you essentially are saying that this field is read only and once its value is assigned it cannot be changed. In our MovieDetail example, we have defined the variable releaseDate using val, once the movie is released, there is no way its release date is going to change, so there is no point in giving the ability to change value once assigned.

var (Read/Write) – When you define a field using var, you essentially are saying that this field is readable as well as writeable, so a new value can be assigned to it at any point of time. In our MovieDetail example, we have defined the rating field using var, as more and more people watch the movie, the rating will change eventually, so we have provided the ability to change the value whenever required.

That is all there is to Data classes in Kotlin, hope you have enjoyed the article.

More about functions in Kotlin

Installation and Hello World in Kotlin

Basic Syntax, Variables and Data Types in Kotlin

Control Flow in Kotlin

Looping in Kotlin