Kotlin é uma linguagem de programação estática e fortemente tipada, o que significa que os tipos das variáveis são verificados em tempo de compilação.
Tipos de Dados
Os tipos de dados numéricos básicos incluem Byte, Short, Int, Long, Float e Double. O tipo String represneta sequências de caracteres.
val mensagem: String = "Olá, mundo!"
val codigo: Int = 2023
val pi: Double = 3.14159
// Conversão de tipos
val inteiroParaDecimal = codigo.toFloat()
val decimalParaInteiro = pi.toInt()
Declaração de Variáveis
Utiliza-se val para referências imutáveis (similar ao final em Java) e var para referências mutáveis. É recomendável priorizar o uso de val.
val nomeSistema: String = "Alpha" // Imutável
var contador: Int = 0 // Mutável
contador = 1 // Válido
// nomeSistema = "Beta" // Erro de compilação
Segurança de Nulo
Por padrão, os tipos em Kotlin não aceitam valores nulos. Para permitir nulos, adiicona-se um sufixo ? ao tipo.
var nomeOpcional: String? = null
var nomeObrigatorio: String = "Inválido" // Não pode ser null
// Acesso seguro com operador ?.
val comprimento = nomeOpcional?.length // Retorna null se nomeOpcional for nulo
// Operador Elvis ?:
val valorSeguro = nomeOpcional ?: "Padrão"
Estruturas de Controle
if pode ser usado como expressão que retorna um valor. when é uma alternativa poderosa para múltiplas condições.
val resultado = if (x > y) x else y
when (objeto) {
is String -> println("É uma string de comprimento ${objeto.length}")
1, 2, 3 -> println("Valor pequeno")
else -> println("Outro caso")
}
Loops for iteram sobre intervalos ou coleções.
for (item in lista) { /* ... */ }
for (indice in 0 until 10) { /* ... */ }
Funções
Funções são declaradas com a palavra-chave fun. Podem ter parâmetros com valores padrão.
fun calcularAreaComprimento(largura: Double, altura: Double = 2.0): Double {
return largura * altura
}
// Chamada usando o valor padrão
val area = calcularAreaComprimento(5.0) // altura será 2.0
Funções de expressão única permitem sintaxe simplificada.
fun soma(a: Int, b: Int) = a + b
Funções de Alta Ordem e Lambda
Funções podem receber outras funções como parâmetros ou retorná-las. Lambda expressões são literais de função.
fun aplicarOperacao(x: Int, y: Int, operacao: (Int, Int) -> Int): Int {
return operacao(x, y)
}
val somaLambda = { a: Int, b: Int -> a + b }
val total = aplicarOperacao(4, 5, somaLambda) // Resultado: 9
// Usando referência de função
fun multiplicar(a: Int, b: Int): Int = a * b
val produto = aplicarOperacao(3, 4, ::multiplicar)
Quando uma lambda é o último parâmetro, ela pode ser escrita fora dos parênteses (sintaxe trailing lambda).
aplicarOperacao(2, 3) { a, b -> a * b }
Programação Orientada a Objetos
Classes e Construtores
class Veiculo(val marca: String, var modelo: String) {
var quilometragem: Double = 0.0
private set
fun dirigir(distancia: Double) {
quilometragem += distancia
}
}
// Instanciação
val meuCarro = Veiculo("Toyota", "Corolla")
meuCarro.dirigir(150.5)
Herança e Polimorfismo
Classes são final por padrão. Use open para permitir herança.
open class Forma(val nome: String) {
open fun area(): Double = 0.0
}
class Circulo(val raio: Double) : Forma("Círculo") {
override fun area() = Math.PI * raio * raio
}
Interfaces
interface Desenhavel {
fun desenhar()
fun preencher(cor: String) { // Implementação padrão
println("Preenchendo com cor $cor")
}
}
class Quadrado : Desenhavel {
override fun desenhar() {
println("Desenhando quadrado")
}
}
Classes de Dados
Simplificam a criação de classes que servem principalmente para armazenar dados.
data class Ponto(val x: Double, val y: Double)
// Métodos equals(), hashCode(), toString(), copy() e componentN() gerados automaticamente
Objetos Companheiros
Substituem os membros estáticos de Java.
class Configuracao {
companion object {
const val VERSAO = "1.0"
fun criarPadrao() = Configuracao()
}
}
val config = Configuracao.criarPadrao()
val versao = Configuracao.VERSAO
Recursos Avançados
Funções de Extensão
Permitem adicionar funções a classes existentes sem modificá-las.
fun String.removerEspacosExcedentes(): String = this.trim().replace(" ", " ")
val texto = " Olá mundo ".removerEspacosExcedentes() // "Olá mundo"
Delegação (by)
by lazy inicializa uma propriedade na primeira vez que é acessada, de forma thread-safe.
val bancoDeDados: Conexao by lazy {
Conexao("jdbc:meubanco://localhost")
}
// Conexão estabelecida apenas na primeira chamada a bancoDeDados
Escopo de Classes Seladas
Limitam hierarquia a um conjunto fixo de subclasses, úteis com when.
sealed class ResultadoOperacao
class Sucesso(val dados: String) : ResultadoOperacao()
class Erro(val excecao: Exception) : ResultadoOperacao()
fun processarResultado(resultado: ResultadoOperacao) = when (resultado) {
is Sucesso -> println("Dados: ${resultado.dados}")
is Erro -> println("Erro: ${resultado.excecao.message}")
}
Null Safety Avançada
Use o operador !! com cautela, pois lança NullPointerException se o valor for nulo.
val textoNaoNulo: String = textoPotencialmenteNulo!!
// Assegura ao compilador que textoPotencialmenteNulo não é nulo (risco em runtime)