Por que o Kotlin foi criado?
Vamos descobrir os motivos por trás da criação dessa linguagem, quais problemas seus criadores queriam resolver e quais suas vantagens sobre o Java.
Recentemente foi anunciado durante o Google I/O 2017 que o Android dará suporte oficial para o Kotlin, linguagem de programação criada pela JetBrains que roda na JVM, Android e JavaScript. Muitos programadores já adotavam ela em seus projetos em produção antes mesmo do anuncio oficial e depois do anuncio da Google a popularidade do Kotlin aumentou muito, mas o que o Kotlin está trazendo de benefícios para os programadores?
Vamos começar entendendo as motivações da JetBrains para depois entendermos quais problemas o Kotlin resolve.
Os motivos da JetBrains
Quando a empresa começou a desenvolver o Kotlin em 2011 eles, a equipe do JetBrains, estavam cientes que iriam levar muito tempo para alcançar seus objetivos, então eles sabiam das dificuldades e custos, mas seus objetivos eram proporcionalmente grandes.
A JetBrains é uma empresa que desenvolve diversas ferramentas para desenvolvedores, desde IDEs até ferramentas de Integração Continua e Code Review, e um de seus produtos mais famoso está o IntelliJ IDEA, uma poderosa IDE para a linguagem Java.
O primeiro problema que a JetBrains estava enfrentando era com sua produtividade. Apesar da empresa dar suporte completo para outras linguagens baseadas na JVM como Scala e Groovy, a maior parte do seu do código é feito utilizando a linguagem Java.
Para aumentar sua produtividade eles precisariam utilizar uma linguagem de programação mais expressiva, que fosse capaz de resolver certos problemas que o Java possui dificuldade, mas eles não podiam adotar uma nova linguagem por causa da curva de aprendizado e na época as alternativas mais populares como Groovy não possuía uma boa interoperabilidade e também era dinâmica, então seria muito complicado fazer uma migração gradual.
Eles precisavam de uma linguagem que fosse mais expressiva, a curva de aprendizado deveria ser fácil, a linguagem deveria ser capaz de interoperar com o código existem em Java, que tivesse um tempo de compilação curto, e que tirasse proveito dos pontos fortes da linguagem Java e da JVM, incluindo os grandes frameworks como Hibernate e Spring, então a partir disso que eles começaram o desenvolvimento do Kotlin.
Outro grande objetivo da JetBrains é financeiro. Como consequência de buscar uma ferramenta mais poderosa que pode trabalhar em conjunto com código Java, a JetBrains também está investindo muito na integração da linguagem Kotlin com sua IDE, o que consequentemente vai impulsionar suas vendas.
Quais as melhorias
A JetBrains queria criar uma linguagem com os pontos forte da linguagem Java e evitar alguns problemas que a linguagem Java traz. O Java, por questões de compatibilidade, acabou adotando muitos problemas de design. Algumas decisões de design deixaram a evolução da linguagem muito engessada, o que tornou muito difícil a implementação de novas funcionalidades.
Todo novo recurso lançado para a linguagem Java precisa ser feito com extrema cautela para não quebrar as aplicações que rodam na JVM e muitas vezes é necessário um certo malabarismo, uma jogada de mestre, com essas limitações para implementar novas funcionalidades, como foi o caso das Interfaces Funcionais que tornou possível a implementação das Expressões Lambda no Java 8. Foi uma ótima sacada da equipe de engenheiros da linguagem, mas por causa dessa promessa de manter a retrocompatibilidade, um dos pontos forte da plataforma Java, muitas funcionalidades novas acabam demorando algum tempo para serem lançados.
Muitas linguagens sofrem com esse problema e não é um problema exclusivo da linguagem Java. Algumas linguagens tomam medidas extremas como quebrar a compatibilidade com as versões anteriores, como é o caso do Python que possui a versão 2.x e 3.x que são incompatíveis entre si, e para a plataforma Java que preza pela retrocompatibilidade isso seria algo inaceitável. Também temos o JavaScript como grande exemplo de linguagem que possui diversas limitações e que evolui à pequenos passos pois qualquer colisão de palavras entre a linguagem e um framework poderia quebrar uma parte internet.
Então a grande vantagem do Kotlin sobre o Java é que ele é algo totalmente novo. No temos as mesmas limitações que o Java ainda. Nós conhecemos os problemas de design das linguagens antigas, nós sabemos seus pontos fortes, e temos uma empresa focada nas necessidades do mercado para desenvolvê-la.
A documentação completa do Kotlin cita vários itens do livro Effective Java escrito por Joshua Bloch, que comenta boas práticas para utilizar a linguagem Java e formas de evitar problemas comuns, deixando claro a forte influência do livro no design da linguagem. Dessa forma Kotlin corrigiu alguns problemas muito conhecidos do Java:
1. As referências Null são controladas pelo sistema de tipos
Em Kotlin você é forçado pela linguagem a tratar toda variável e função que possa conter null
. Isso é um recurso da linguagem conhecido como Null-safety. Isso elimina quase todas as possibilidades possíveis de ter uma NullPointerException
pois precisamos declarar previamente se uma variável ou função pode ou não receber um null
.
Normalmente programar de forma defensiva é uma má prática, afinal temos que garantir a integridade dos dados a todo momento, mas como se trata de um recurso da própria linguagem nós não precisamos criar diversos if
s para checar se uma variável é null
. Por exemplo, em Java teríamos que fazer algo do tipo:
void somaNumero(Integer numero) {
System.out.println(numero + 10); // Código compila, mas lança NullPointerException caso numero seja null
}
Em Kotlin teríamos que declarar que uma variável ou parâmetro pode receber null
colocando um ?
como sufixo no tipo, por exemplo:
fun somaNumero(numero: Int?) {
println(numero + 10) // Código não compila, pois o parâmetro pode ser nulo.
}
Isso é algo muito bom pois é impossível atribuir um valor null
para qualquer variável a não ser que ela esteja anotada adequadamente com o ?
no final da declaração, um sufixo:
val nome: String? = null; // Compila. String?, com o ? como sufixo, pode receber um null.
val sobrenome: String = null; // Erro. String, sem ? como sufixo, não pode receber null.
Ou seja, em tempo de compilação o programador tem ciência e feedback imediato se determinado método ou variável permite nulo ou não. Além disso, construir APIs com este recurso torna o desenvolvimento mais simples.
2. Sem Raw Types nos Generics
Na versão 1.2 do Java foi introduzido as Collections, uma série de interfaces, classes e algoritmos para trabalhar com coleções de objetos, como a List
, Queue
e Set
. O problema das Collections é que elas podiam receber qualquer tipo de objeto e sempre que você fosse utilizar esse objeto você era obrigado à fazer o Cast e com o risco de ter problemas com NullPointerException
por causa da mistura de objetos. Repare no exemplo abaixo
void collectionBeforeGenerics() {
// Problema: Não deixa explícito o tipo que contém na List.
List pessoas = Arrays.asList("Kewerson", "Handerson", "Rafael");
pessoas.add(10); // Problema: Aceita qualquer tipo além de String.
Iterator iter = pessoas.iterator();
while (iter.hasNext()) {
String pessoa = (String) iter.next(); // Problema: Cast obrigatório.
System.out.println(pessoa.length()); // Problema: o método length() é especifico de String, então teremos uma exception.
}
}
Na versão 1.5 do Java foi introduzido os Generics, que vinham para resolver esse problema de falta de tipos das Collection através do Type Parameter da Classe, que iria declarar com qual tipo a Collection iria trabalhar passando o tipo dentro do operador diamante (<>
) , por exemplo List<String> pessoa = new ArrayList<>()
. Dessa forma não temos mais a necessidade de fazer o Cast e também não seria possível adicionar um objeto diferente do tipo informado dentro do <>
. Repare no exemplo abaixo:
void collectionAfterGenerics() {
// Deixa explícito que a List é de Strings
List<String> pessoas = Arrays.asList("Kewerson", "Handerson", "Rafael");
// pessoas.add(10); // Causa erro de compilação. Somos obrigados à passar uma String.
Iterator iter = pessoas.iterator();
while (iter.hasNext()) {
System.out.println(pessoa); // Não precisamos fazer o cast.
}
}
O problema que simplesmente adicionar essa nova sintaxe faria todos os softwares criados utilizando Collections da versão 1.2 quebrarem e isso é algo que a Oracle não queria, então foi decidido que a antiga sintaxe para criar uma Collection seria mantida em conjunto com a nova, e a antiga declaração das Collections, sem utilizar o operador dimante <>
, seria conhecida como Raw Types.
Resumindo: As Raw Types são a declaração de uma classe que utiliza Generic em Java, como uma List
, sem especificar um tipo como parâmetro, como por exemplo List<String>
.
Os Raw Types são um grande problema, mas por motivos de compatibilidades eles tiveram que ser mantidos no Java, mas o Kotlin por ser uma linguagem nova não possui mais esse problema.
3. Arrays são invariantes
Os Arrays serem invariantes significa que todos tipos de Arrays são incompatíveis. Você não pode atribuir um Array de Strings para um Array de Objects como em Java. O exemplo abaixo é um código válido em Java:
String[] strings = new String[10];
Object[] obj = strings;
Esse código compila normalmente, pois o Java também considera o Array de Strings uma extensão do Array de Objects , mas nós teríamos que verificar todos os valores e fazer o Cast dos objetos sobre o risco de disparar um NullPointerException
. Isto é um erro de design do Java por conta da necessidade de manter a retrocompatibilidade.
4. Kotlin possui Function Type ao invés de conversão de Single Abstract Methods como no Java
Nas maioria das linguagens funcionais as funções são tratadas de forma especial, com seus próprios operadores e propriedades, elas são conhecidas como First-class Function (Função de primeira classe), então você é capaz de atribuir funções para variáveis, passar funções como parâmetro e fazer funções retornarem outras funções.
Quando o Kotlin foi lançado a linguagem Java não tinha essa funcionalidade, e para se passar uma função como parâmetro de outra função era necessário criar uma classe anonima com apenas um método, uma Single Abstract Method, que muitas vezes deixa o código muito verboso e simular First-class Functions, precisando criar sempre uma nova interface com a assinatura adequada da função.
Atualmente temos o Java 8 possui as Interfaces Funcionais e as Expressões Lambda, que ajudaram a diminuir muito a verbosidade das classes anonimas com a utilização das expressões Lambda, mas por baixo dos panos ele está fazendo a mesma coisa que fazíamos do Java 8.
Já no Kotlin as funções são First-class Function, então a referência da função pode ser passada como parâmetro para outras funções, podem ser atribuídas para variáveis e também podemos retornar ela das funções. Isso facilita muito trabalhar com o paradigma funcional.
5. Kotlin não possui checked exception
Checked exceptions é um assunto controverso. Algumas pessoas amam e outras pessoas odeiam. O time da JetBrains optou por remover as checked exceptions pois nem sempre o Cliente da API vai poder lidar com a exceção, então de nada adianta forçar que ele trate uma checked exception. Para a JetBrains quem deve decidir como uma exceção vai ser tratada é o Cliente da API e não o designer dela.
6. Maior expressividade e segurança
Além de resolver esses problemas comuns da linguagem Java, o Kotlin também traz diversos novos recursos para tornar a linguagem mais expressiva e mais segura como a checagem de tipos Null explícita pela linguagem conhecida como Null-safety, keyword de override obrigatória nos métodos, parâmetros nomeados que eliminam a necessidade do padrão Builder, entre outros. Existem diversas novas funcionalidades na linguagem que nos auxiliam durante o desenvolvimento de uma aplicação, mas vamos deixar para falar deles em outro artigo.
Conclusão
O Kotlin traz diversas vantagens em relação ao Java por ser uma linguagem mais nova, e por ela estar nas mãos da JetBrains teremos uma linguagem que preenche as necessidades atuais do mercado.
Como consequência das boas decisões dos designers da linguagem, temos uma linguagem concisa com a possibilidade de interoperar código Kotlin com Java e Java com Kotlin, sendo possivel utilizar até mesmo os frameworks Java como Hibernate, SpringMVC, JSF etc, o que possibilita uma adoção gradual em projetos em produção. Podemos utilizar o Kotlin em qualquer lugar onde utilizaríamos o Java, desde projetos Desktop até os projetos Web e Android.
A JetBrains criou o Kotlin com o objetivo de ser melhor que o Java e demonstra um grande potencial de tornar isso realidade, mas não é algo que vai acontecer tão rapidamente. Você ainda precisa conhecer muito bem o Java para interoperar com o Kotlin, então se você pretende começar na plataforma Java, ou mais precisamente no Android, você precisa aprender a utilizar os recursos da plataforma. É importante entender o que está sendo feito ao mesmo tempo que mantém a legibilidade do código, pois escrever menos ou mais não é sinônimo de qualidade.
Nem sempre escrever poucas linhas quer dizer vantagem ou legibilidade. Escrever menos ou mais não é o problema, entender o que está fazendo e ter legibilidade é o que importa. by Handerson Frota.
O mercado leva tempo para adotar novas soluções, então não se afobe e não pule etapas.
Para começar a testar o Kotlin, dá uma olhada no Kotlin Koans, uma série de desafios criados pela JetBrains para ensinar a sintaxe e os principais recursos da linguagem.
Se você tiver interesse em aprender mais sobre a plataforma Android, dá uma olhada no nosso curso de Android aqui da TriadWorks onde ensinamos toda a base e filosofia da plataforma que vão te colocar no caminho certo para desenvolver aplicações Android, seja utilizando Java ou Kotlin.
E você, já conhece o Kotlin? Deixe sua opinião sobre essa nova linguagem e quais são suas expectativas para o futuro da plataforma Java.
You might also be interested in these articles...
Desenvolvedor na TriadWorks - Email