Paulo Enoque
Kotlin para Android
6 min readDec 10, 2017

--

Serie sobre Kotlin Para Android:

  1. Introdução a kotlin

2. Sintaxe básica do Kotlin (Estamos aqui)

3. Detalhes avançados sobre kotlin

4. Kotlin Android Extensions

Sintaxe básica do Kotlin

Como havia prometido, este é o segundo episódio da série Kotlin para Android, diferente do primeiro este artigo será mais prático com exemplos ilustrativos sobre os principais conceitos sobre kotlin, eu até me arriscaria a dizer que depois de ler este artigo você estará preparado para começar a escrever o ser primeiro código kotlin e farei o máximo para o artigo não seja muito longo.

Olá Mundo

Quem sou eu para quebrar a sagrada tradição do “Olá Mundo” no mundo da programação quando aprendemos uma linguagem nova:

fun main(args: Array<String>): Unit {
println(“Olá Mundo!”)
}

parecendo que não, podemos aprender muito com esse pequeno trecho de código:

1. Como vimos no artigo introdutório sobre kotlin, a linguagem usa funções em vez de métodos como estamos habituados em java, uma das vantagens dessa abordagem é que não precisamos de uma classe para que funções existam, isto é, a função acima precisa simplesmente estar num ficheiro .kt para ser compilada e executada;

2. Diferente de java, na assinatura de uma função ou de um parâmetro colocamos primeiro o nome e depois o tipo;

3. Unit equivale a void no java

4. Não é obrigatório colocar (;) no fim de cada instrução

Agora percebo o porquê de não ignorar essa tradição, parecendo que não, podemos aprender muito com ela.

Propriedades (property)

Como boa prática, em java, criamos uma variável privada e criamos também os seus assessores (gets e sets), a isso dá-se o nome de propriedade. Infelizmente apesar de ser uma boa pratica, isso nos leva a ter classes muito verbosas, cheias de código repetitivo. Kotlin traz uma abordagem diferente, não existem variáveis, mas sim propriedades, ou seja, em kotlin quando criamos uma variável estamos na verdade a criar uma propriedade (um campo para armazenar dado, get, set) e fazemos isso numa única expressão.

var mensagem: String//em java seriaprivate String mensagem;public void setMensagem(String mensagem){    this.mensagem = mensagem;}public String getMensagem(){    return this.mensagem;}

Pode-se perceber a diferença de verbosidade entre as duas abordagens e no fim das contas o resultado é o mesmo, e agora o que podemos aprender do trecho acima:

1. A assinatura da declaração das propriedades é similar a da declaração das funções, ou seja, primeiro temos o nome da propriedade e depois o seu tipo separado por (:);

2. Aparece uma palavra nova var, o que será que isso significa?

a. Var variable — para propriedades mutáveis, ou seja, alem do assessor get será também criado um assessor set;

b. Val value — para propriedades não mutáveis, ou seja, será apenas criado a assessor get, o equivalente a final em java, usa-se para valores que não vão mudar.

Quando inicializamos a variável no momento da declaração não existe a necessidade de colocar explicitamente o tipo da variável pois o compilador pode inferir o tipo da variável através do dado recebido:

val mensagem = "Ola Mundo"

isso não quer dizer que podemos colocar qualquer tipo de dados na mesma variável (como nas linguagens dinâmicas como o groovy), o tipo de dados da variável mensagem foi definido de forma implícita (String nesse caso).

Funções

Uma função pode ser declarada em qualquer lugar, não dependendo da existência de uma classe, para perceber melhor vamos criar uma função que imprime “Olá Mundo”:

fun imprime(mensagem: String){    println(mensagem)}fun main(args: Array<String>) {    val mensagem = "Ola Mundo"    imprime(mensagem)}

quando temos apenas uma instrução na função podemos converte-la em single expression function usando o sinal de igualdade:

fun imprime(mensagem: String) = println(mensagem)fun main(args: Array<String>) {    val mensagem = "Ola Mundo"    imprime(mensagem)}

isso ajuda de forma considerável a tornar a linguagem mais concisa pois é simples perceber a intenção do que se pretende fazer sem muito esforço.

Outra funcionalidade interessante é named parameters, essa funcionalidade existe já desde o C# e basicamente permite atribuir valor padrão a um parâmetro:

fun imprime(mensagem: String = "Ola Mundo") = println(mensagem)fun main(args: Array<String>) {    imprime()}

Como não se foi especificado o valor do parâmetro mensagem, ele vai tomar o valor padrão “Ola Mundo”

Controlando o fluxo de dados com condições

O controlador de fluxo de execução do código mais usado é o if, e a sua assinatura é similar com a assinatura na linguagem java, para perceber vamos criar uma função que compara dois números e diz se são iguais ou diferentes:

fun compara(x: Int, y: Int): String{    if (x != y){        return "Diferentes"    }    return "Iguais"}fun main(args: Array<String>) {    println(compara(1,2))}

Mais diferente de java, o if no kotlin é uma expression e não um statement o que quer dizer que ele retorna um valor, é mais simples perceber na prática o que isso quer dizer:

fun compara(x: Int, y: Int): String{    return if (x != y) "Diferentes" else "Iguais"}fun main(args: Array<String>) {    println(compara(1,2))}

agora o código ficou bem mais interessante, e se eu dissesse que ainda podemos melhorar esse código? Lembra que eu disse sobre as single expression functions? Podemos implementar o mesmo nessa função:

fun compara(x: Int, y: Int): String = if (x != y) "Diferentes" else "Iguais"fun main(args: Array<String>) {    println(compara(1,2))}

melhor nem?? Mais ainda não atingimos o potencial máximo da linguagem, o que falta agora? Lembra quando eu disse que o compilador podia inferir o tipo de uma variável quando ela é inicializada no momento da declaração? isso se aplica para as single expression functions:

fun compara(x: Int, y: Int) = if (x != y) "Diferentes" else "Iguais"fun main(args: Array<String>) {    println(compara(1,2))}

muito cool?? Pois bem, esse é apenas um cheirinho do poder do kotlin

Classes e Herança

A maneira de criar uma classe e interface é bem similar com java, vamos abordar somente as diferenças:

class Animal{
fun emitirSom() = "Gggrrrhhh"
}

vamos agora criar uma classe gato que vai estender da classe animal e subscrever o método emitirSom

class Goto constructor(val name: String){}

antes podemos notar que a assinatura do construtor está inclusa na assinatura da classe. Quando não mudamos o encapsulamento do método constructor e nem colocamos nenhuma anotação então podemos melhorar a assinatura do método:

class Goto(val name: String){}

agora se tentássemos estender da classe animal o programa daria um erro de compilação por um motivo simples, as classes e funções são por defeito privadas e finais, o que faz sentido, se é que queremos que uma classe seja estendida devemos marcar como open:

open class Animal{    open fun emitirSom() = "Gggrrrhhh"}class Goto(val name: String) : Animal(){    override fun emitirSom() = "Miauuu"}

O que Podemos aprender com o código acima:

1. Para estender uma classe devemos usar o sinal (:) e inicializar o construtor

2. O marcador override é obrigatório quando queremos subescerver funções

3. Para que uma classe ou função possa ser estendida deve ser marcada como open

Data Classes

Quantas vezes pensamos em criar uma classes pessoa com apenas dois atributos (nome e apelido), e no inicio parece simples, então criamos a classe, de seguida criamos duas variáveis privadas nome e apelido, e de seguida os assessores (gets e sets), e depois o construtor que inicializa as duas variáveis, logo o método hashcode, o método equals, o método copy e o método toString,… Poxa, nós só queríamos uma classe com dois atributos, porquê somos obrigado a colocar esse todo código repetitivo nas nossas classes.

Kotlin resolve isso com as data classes que encapsulam isso tudo numa simples linha, para facilitar a perceção podemos ver um exemplo de como isso seria em java e como seria em kotlin:

import java.util.Objects;public class Pessoa {//    declaracao das variaveis    private String nome;    private String apelido;//  Contructor que inicializa todas as variaveis     public Pessoa(String nome, String apelido) {        this.nome = nome;        this.apelido = apelido;    }//  assessores gets e sets    public String getNome() {        return nome;    }    public void setNome(String nome) {        this.nome = nome;    }    public String getApelido() {        return apelido;    }    public void setApelido(String apelido) {        this.apelido = apelido;    }    @Override    public boolean equals(Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        Pessoa pessoa = (Pessoa) o;        return Objects.equals(nome, pessoa.nome) &&                Objects.equals(apelido, pessoa.apelido);    }    @Override    public String toString() {        return "Pessoa{" +                "nome='" + nome + '\'' +                ", apelido='" + apelido + '\'' +                '}';    }    @Override    public int hashCode() {        return Objects.hash(nome, apelido);    }}

Agora a versão kotlin

data class Pessoa(var nome: String, var apelido: String)

acredite, as duas classes são funcionalmente iguais e desempenham exactamente as mesmas funções e podem ser usadas nas mesmas circunstancias.

Por causa da extensão do artigo melhor parar por aqui, espero por ti no próximo episódio para a semana. Não esqueça daquela base de sempre, dê um clap se achou o artigo útil e para a semana tem mais. E enquanto espera o meu terceiro episódio pode clicar aqui para se informar mais sobre varias comparações em relação a abordagem java e kotlin

--

--