Kotlin tomou o lugar do Java como linguagem oficial do Android e diversas grandes empresas vem migrando seus back-ends de Java para Kotlin. Neste post vou mostrar a você porquê isso vem acontecendo.
O poder do Kotlin
Kotlin é tão poderosa quanto o Java e isso é incrível. No post anterior eu falei um pouco sobre a interoperabilidade entre as duas e contei brevemente a história da linguagem criada pelos engenheiros da Jetbrains. Essa interoperabilidade, aliada ao quão concisa Kotlin é, a torna uma substituta perfeita para a mãe dos legados.
Vamos tomar como exemplo uma classe que representa uma conta corrente em Java e em Kotlin.
Em Java:
Em Kotlin:
É isso mesmo, o código Kotlin acima faz exatamente o que o em Java faz 😱
A ideia da classe ContaCorrente é representar um conta com as seguintes propriedades: um titular, que pode ser mudado, um cpf, uma agência, uma conta, todos imutáveis e um saldo, mutável, é claro. Para construi essa classe em Java respeitando os princípios do encapsulamento, temos que desenvolver os getters e setters necessários, além de criar funções auxiliares como toString()
, copy()
, equals()
e hashCode()
. Mas para fazer isso em Kotlin basta criar uma data class, usar os declaradores de propriedades corretos (var
e val
) e pronto: temos todos os getters e setters necessários além das funções antes mencionadas!
Para verificarmos a veracidade disso, vamos analisar o código abaixo:
Nesse programa Kotlin nós instanciamos as duas classes que representam uma conta corrente e chamamos todos os seus métodos para compararmos seus poderes de abstração. Repare que para acessar os getters e setters em Kotlin, basta usarmos a notação de .
. Eis a saída:
Ronaldo
João
022.521.260-94
69624
246964
10000.0
12000.0
ContaCorrenteKt(titular=João, cpf=70116672293, agencia=69624, conta=246964, saldo=12000.0)
152796811
false
Ronaldo
João
022.521.260-94
69624
246964
10000.0
12000.0
ContaCorrenteJava(titular=João, cpf=70116672293, agencia=69624, conta=246964, saldo=12000.0)
181425962
false
ContaCorrenteKt(titular=João, cpf=70116672293, agencia=69624, conta=246964, saldo=12000.0)
ContaCorrenteJava(titular=João, cpf=70116672293, agencia=69624, conta=246964, saldo=12000.0)
Como podemos ver, ambas tem o mesmo poder de abstração, mas a diferença de verbosidade entre as duas é gigante! E esse é um pequeno gostinho do porquê Kotlin é cada vez mais adotado quando comparada a Java.
Var e Val
Você deve ter reparado que usamos diversas vezes duas palavras-chaves muito importantes em Kotlin: var
e val
. E o que elas significam? Basicamente, essa é a notação que a linguagem usa para declarar propriedades que são mutáveis e aquelas que são imutáveis.
Ao declarar uma propriedade como var
(vem de variable), queremos dizer que ela é mutável e ganhamos de brinde os seus setter e getter de forma implícita, ela corresponde a uma variável em Java com seus métodos getter e setter.
Ao declarar uma propriedade como val
(vem de value), queremos dizer que ela é imutável e, é claro, já temos seu método getter implementado implicitamente. Desse modo, ela corresponde a uma variável final em Java com seu getter já desenvolvido.
É importante salientar que apesar das propriedades já virem com seus getters e setters implementados, não significa que nós não podemos customizá-los. Vamos implementar uma nova propriedade na nossa classe de conta corrente e criar um getter customizado. Essa propriedade representa a resposta para a pergunta: “a conta está negativada?”, true
para sim e false
para não. Dessa forma basta que o getter dessa propriedade seja a comparação entre o saldo da conta e zero:
E pronto: já temos um getter customizado! Agora para fazer um setter customizado vamos implementar um setter para a propriedade saldo. A lógica é a seguinte: o saldo só será alterado se o valor passado para o setter for positivo:
Feito. Repare que antes de implementar o setter, tivemos que inicializar a propriedade, isso foi necessário pois o setter usa o valor da propriedade para fazer a atribuição, por isso ela não pode ser nula. E quanto a palavra-chave field
, ela representa a própria propriedade, é algo parecido ao usar this.saldo
em Java.
Funções
Como já deve ter percebido, para se declarar uma função em Kotlin, usamos a palavra-chave fun
, pra você ver como é divertido programar em Kotlin 🤣. Além disso a função chamada main
é a função especial que indica onde o programa deve começar a ser executado. Agora vamos analisar de forma mais profunda a sintaxe das funções com um exemplo do Kotlin in Action:
Assim como em Java, o nome da função vem logo no início, nesse caso max
, depois entre parênteses temos seus parâmetros na forma <nome>: <Tipo>
, em seguida após os dois pontos o tipo de retorno da função e por fim, entre chaves, o seu corpo em si. Essa função compara dois valores e retorna o maior. Repare que em Kotlin o if
não é uma declaração (statement), mas sim uma expressão, ou seja, ela tem um valor, que está atrelado às suas comparações lógicas. No caso acima, se a
for maior que b
, o valor da expressão será a
, caso contrário será b
, e é por isso que a expressão pode ser retornada.
Obs: existe outra forma mais concisa de escrever a função max
em Kotlin:
O =
substitui o tipo de retorno da função, as chaves e a palavra-chave return
. Muito legal, né?
Null safety
Para fechar com chave de ouro vamos falar sobre uma das melhores qualidades do Kotlin: sua segurança. Você, pessoa desenvolvedora Java, quantos vezes já não se deparou com o maldito NullPointerException
? Pois saiba que com Kotlin seus problemas acabaram, ou quase isso.
Nessa tão querida linguagem, nós podemos declarar propriedades como nuláveis ou não-nuláveis (em português isso fica bem feio, mas em inglês é nullable e non-nullable), da seguinte forma:
Para acessar a propriedade nome
, não temos nenhum problema, pois sabemos que ela não pode ser nula. Mas e quanto a propriedade `sobrenome? Em Java, seria necessário fazer o seguinte:
if(sobrenome != null) System.out.println(sobrenome.length());
Mas em Kotlin, nós temos uma feature muito útil chamada safe call
. De modo que o código acima pode ser reduzido ao seguinte:
println(sobrenome?.length)
Trata-se da notação ?.
, ela garante que estamos acessando uma propriedade que não está nula no momento, do contrário retorna apenas null. Essa notação é muito útil em chamadas encadeadas como o seguinte exemplo de kotlinlang.org:
bob?.department?.head?.name = managersPool.getManager()
Se qualquer uma das propriedade da cadeia for nula, essa atribuição é pulada e não considerada.
Mas e para o caso de eu querer fazer uma atribuição de uma propriedade non-nullable para uma propriedade nullable? Você poderia fazer o seguinte:
val l: Int = if (b != null) b.length else -1
Porém veja que mais uma vez precisamos de uma expressão inteira para uma simples atribuição. Foi pensando em solucionar isso que Kotlin tem o brilhante Elvis operator!
val l: Int = b?.length ?: -1
Nome criativo, não? Esse operador ?:
serve para avaliar se a expressão à esquerda é nula, caso ela não seja, ele a retorna, caso seja, ele retorna o operador à direita!
Agora, se mesmo com todas essas opções você ainda quiser ver um NullPointerException
, Kotlin deixa, basta usar o operador !!
:
val l = b!!.length
Nesse caso, se b
não for nulo, seu valor será retornado, mas caso seja, uma NullPointerException
será lançada!
Próximos posts
E por hoje é isso, pessoal! Conseguimos falar um pouco sobre Kotlin, mas faltam alguns conceitos importantes como as clássicas expressões for
, while
, uma expressão nova chamada when
, entre outras que vamos discutir no próximo post sobre Kotlin.
Obrigado pela atenção, até a próxima!
Post anterior:
Breve história do Kotlin
Ronaldo Costa de Freitas ・ Oct 25 '22 ・ 3 min read
Próximo post:
Top comments (0)