Classe de Dados Kotlin

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

Classe Kotlin Data

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 sobre o 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, métodos toString(), equals() e hashCode(). Com as práticas de arquiteturas limpas e separação de práticas de código em nossos projetos, 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)

É ISSO. Kotlin converte um código Java de 96 linhas para 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 em Kotlin

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

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

Métodos internos da Classe de Dados em Kotlin

A classe de dados em 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 em Kotlin

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

  • 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 herança (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, como 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 Classes 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 possui 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 aqueles que não são padrão e aqueles que desejamos usando o argumento nomeado. Usando argumentos nomeados, podemos definir o quinto argumento como o segundo, especificando explicitamente o nome do parâmetro seguido por =. A vida fica tão mais fácil desta forma!

Método toString() da Classe de Dados em 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())


}

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

Nota: A função print adiciona implicitamente um toString().

Método copy() da Classe de Dados Kotlin

A função copy() é usada para criar uma cópia de uma instância da classe de dados com algumas propriedades modificadas. Recomenda-se 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 multithread. 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)
}
//O seguinte é impresso no console.
//Livro(nome=Tutoriais Android, autor=Anupam, últimaModificação=1234567, classificação=4.5, downloads=1000)
//Livro(nome=Kotlin, autor=Anupam, últimaModificação=1234567, classificação=4.5, downloads=1000)

Classe de Dados Kotlin equals() e 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 true se o hashCode() for igual, caso contrário, retorna false.

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")

}

// O seguinte é impresso 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.

Declarações de Destruição

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, conforme 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 private for definido em qualquer um dos argumentos, 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 uma rápida visão geral das Classes de Dados em Kotlin. Referências: Documentação do Kotlin

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