Classe de Dados Kotlin

Neste tutorial, vamos dar uma olhada na Data Class do Kotlin. Se você ainda não leu o post sobre Classes Kotlin, recomendamos que o faça antes de prosseguir.

Data Class Kotlin

Você fica cansado de escrever milhares de linhas de código para suas classes de dados POJO em Java? Todo programador Java em algum momento deve ter feito uma nota do número de linhas de código que eles precisam escrever para classes que apenas precisam armazenar alguns dados. Vamos ver como uma classe POJO Book.java se parece:

public class Book {

    private String name;
    private String authorName;
    private long lastModifiedTimeStamp;
    private float rating;
    private int downloads;


    public Book(String name, String authorName, long lastModified, float rating, int downloads) {
        this.name = name;
        this.authorName = authorName;
        this.lastModifiedTimeStamp = lastModified;
        this.rating = rating;
        this.downloads = downloads;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

    public long getLastModifiedTimeStamp() {
        return lastModifiedTimeStamp;
    }

    public void setLastModifiedTimeStamp(long lastModifiedTimeStamp) {
        this.lastModifiedTimeStamp = lastModifiedTimeStamp;
    }

    public float getRating() {
        return rating;
    }

    public void setRating(float rating) {
        this.rating = rating;
    }

    public int getDownloads() {
        return downloads;
    }

    public void setDownloads(int downloads) {
        this.downloads = downloads;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Book that = (Book) o;

        if (downloads != that.downloads)
            return false;
        if (name != null ? !name.equals(that.name) :
                that.name != null) {
            return false;
        }
        return authorName != null ?
                authorName.equals(that.authorName) :
                that.authorName == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (authorName != null ?
                authorName.hashCode() : 0);
        result = 31 * result + downloads;
        return result;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + authorName + '\'' +
                ", lastModifiedTimestamp='" + lastModifiedTimeStamp + '\'' +
                ", rating='" + rating + '\'' +
                ", downloads=" + downloads +
                '}';
    }
}

UAU! São 96 linhas de código apenas para armazenar 5 campos em um objeto. Não estamos fazendo muito aqui além de ter getters, setters, os métodos toString(), equals() e hashCode(). Com as arquiteturas limpas e a separação das práticas de código em nossas práticas, precisamos criar classes POJO, já que todo projeto precisa armazenar dados em algum lugar. Isso pode aumentar o código de boilerplate. É aqui que o Kotlin entra em ação, com o uso de Data Classes. Data Classes são a resposta do Kotlin para reduzir o código de boilerplate. A classe POJO acima pode ser escrita em Kotlin da seguinte maneira:

data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

SÓ ISSO. O Kotlin converte um código Java de 96 linhas em uma única linha de código. Esta é a maneira do Kotlin de reduzir o código de boilerplate em seu projeto!

Criando Classe de Dados Kotlin

A seguir estão os requisitos para criar uma classe de dados Kotlin.

  • Você precisa adicionar a classe com a palavra-chave data
  • O construtor primário precisa ter pelo menos um parâmetro.
  • Cada parâmetro do construtor primário deve ter um val ou um var atribuído. Isso não é o caso com uma classe normal, onde especificar um val ou um var não é obrigatório.
  • As classes de dados não podem ser adicionadas com abstract, open, sealed ou inner

Métodos incorporados da Classe de Dados Kotlin

A classe de dados Kotlin cria automaticamente as seguintes funções para você.

  • equals() e hashCode()
  • toString() no formato "Livro(nome=JournalDev, nomeAutor=Anupam)"
  • Funções componentN() para cada um dos parâmetros na ordem especificada. Isso é conhecido como declarações de desestruturação.
  • copy()

Recursos da Classe de Dados Kotlin

A seguir estão alguns recursos que uma Classe de Dados fornece.

  • Para criar um construtor sem parâmetros, especifique valores padrão para cada um dos parâmetros presentes no construtor primário.

  • Uma Classe de Dados permite a subclasse (Não é necessário mencionar a palavra-chave open).

  • Você pode fornecer implementações explícitas para as funções equals(), hashCode() e toString().

  • Implementações explícitas para as funções copy() e componentN() não são permitidas.

  • Podemos controlar a visibilidade dos getters e setters especificando os modificadores de visibilidade no construtor, conforme mostrado abaixo.

    data class Livro(var nome: String, private var nomeAutor: String, var ultimaModificacao: Long, var avaliacao: Float, var downloads: Int)
    
  • Um parâmetro val não terá um setter definido implicitamente (não pode ser feito explicitamente também!).

Argumentos Padrão e Nomeados em Classe de Dados

Aqui está nossa classe de dados:

data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

Nenhum dos parâmetros tem um valor padrão definido. Portanto, precisamos definir um argumento para cada um deles na instanciação, como mostrado abaixo.

fun main(args: Array<String>) {
val book = Book("Android Tutorials","Anupam", 1234567, 4.5f, 1000)
}

Vamos definir alguns argumentos padrão e ver como a instanciação muda.


data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)
fun main(args: Array<String>) {
var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    book = Book("Kotlin")
    book = Book("Swift",downloads = 500)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    book = Book("Python","Shubham",rating = 5f)

}

Em vez de definir cada argumento, podemos definir apenas os que não são padrão e aqueles que desejamos usando o argumento nomeado. Usando Argumentos Nomeados, podemos definir o 5º argumento como o segundo explicitamente especificando o nome do parâmetro seguido por =. A vida é muito mais fácil assim!

Método toString() da Classe de Dados Kotlin

O método toString() é criado implicitamente e imprime os nomes e rótulos dos argumentos para a instância, como mostrado abaixo.

data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)


fun main(args: Array) {

    var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)
    book = Book("Kotlin")
    println(book)
    book = Book("Swift",downloads = 500)
    println(book)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    println(book.toString())
    book = Book("Python","Shubham",rating = 5f)
    println(book.toString())


}

//A seguir é impresso no console.
//Livro(nome=Tutoriais Android, autor=Anupam, últimaModificação=1234567, avaliação=4.5, downloads=1000)
//Livro(nome=Kotlin, autor=Anupam, últimaModificação=1234567, avaliação=5.0, downloads=1000)
//Livro(nome=Swift, autor=Anupam, últimaModificação=1234567, avaliação=5.0, downloads=500)
//Livro(nome=Java, autor=Pankaj, últimaModificação=1234567, avaliação=5.0, downloads=1000)
//Livro(nome=Python, autor=Shubham, últimaModificação=1234567, avaliação=5.0, downloads=1000)

Nota: print function adiciona implicitamente um toString().

Método copy() da Data Class Kotlin

A função de cópia é usada para criar uma cópia de uma instância da data class com algumas propriedades modificadas. É recomendável usar parâmetros val no construtor de classes de dados para utilizar propriedades imutáveis das instâncias. Objetos imutáveis são mais fáceis ao lidar com aplicativos multi-threaded. Portanto, para criar uma cópia de um objeto imutável alterando apenas algumas propriedades, a função copy() é útil.

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)

    val newBook = book.copy(name = "Kotlin")
    println(newBook)
}
//A seguir é impresso no console.
//Livro(nome=Tutoriais Android, autor=Anupam, últimaModificação=1234567, avaliação=4.5, downloads=1000)
//Livro(nome=Kotlin, autor=Anupam, últimaModificação=1234567, avaliação=4.5, downloads=1000)

Kotlin Data Class equals() and hashCode()

O método hashCode() retorna o código hash para o objeto. Se dois objetos são iguais, hashCode() produz o mesmo resultado inteiro. Portanto, equals() retorna verdadeiro se o hashCode() for igual, caso contrário, retorna falso.

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println("Hashcode is ${book.hashCode()}")

    val newBook = book.copy(name = "Kotlin")
    println("Hashcode is ${newBook.hashCode()}")

    val copyBook = book.copy()
    println("Hashcode is ${copyBook.hashCode()}")


    if(copyBook.equals(book))
        println("copyBook and book are equal")

    if(!book.equals(newBook))
        println("newBook and book are NOT equal")

}

//A seguinte saída é impressa no console.
//Hashcode é 649213087
//Hashcode é 1237165820
//Hashcode é 649213087
//copyBook e book são iguais
//newBook e book NÃO são iguais

Os códigos hash do primeiro e terceiro objetos são iguais, portanto, eles são iguais. Nota: O método equals() é equivalente a == em Kotlin.

Destructuring Declarations

A função componentN() nos permite acessar cada um dos argumentos especificados no construtor, na ordem especificada. N é o número de parâmetros no construtor.

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    println(book.component1()) //Android tutorials
    println(book.component2()) //Anupam
    println(book.component3()) //1234567
    println(book.component4()) //4.5
    println(book.component5()) //1000
    
}

As declarações de destruição nos permitem acessar os argumentos como propriedades do objeto da classe, como mostrado abaixo.

data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book
}

Nota: Se um modificador de visibilidade como privado for definido em qualquer um dos argumentos, ele não pode ser acessado na função acima.

data class Book(val name: String,private val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book //This won't compile since authorName is private
}

Isso é tudo para um resumo rápido sobre Classes de Dados em Kotlin. Referências: Documentação do Kotlin

Source:
https://www.digitalocean.com/community/tutorials/kotlin-data-class