Aula 03: Introdução ao Kotlin para Desenvolvimento Android
Introdução ao Kotlin
Kotlin é uma linguagem moderna e concisa, totalmente interoperável com Java, e é a linguagem oficial para desenvolvimento Android.
Vantagens do Kotlin:
- Sintaxe concisa e expressiva;
- Segurança contra NullPointerExceptions;
- Suporte a programação funcional;
- Interoperabilidade com Java;
- Coroutines para programação assíncrona;
Exemplo 1: Olá, Mundo!
fun main() {
println("Olá, Mundo!")
}
A função main
é o ponto de entrada do programa Kotlin. A palavra-chave fun
indica a definição de uma função, main
é o nome da função, e os parênteses ()
indicam que ela não recebe argumentos. O corpo da função é delimitado por {}
.
Variáveis e Tipos de Dados
Em Kotlin, variáveis podem ser declaradas de duas formas principais:
val
(imutável, equivalente afinal
em Java)var
(mutável, pode ter seu valor alterado posteriormente)
Exemplo 2: Declarando variáveis
val nome: String = "João"
var idade: Int = 25
idade = 26 // Permitido pois "idade" é mutável
A sintaxe segue o formato val/var nome: Tipo = valor
. O tipo pode ser inferido automaticamente pelo compilador.
Controle de Fluxo
O controle de fluxo em Kotlin é essencial para definir a lógica de execução dos programas. Ele permite que o código tome decisões e repita ações com base em condições específicas. As principais estruturas de controle de fluxo em Kotlin incluem:
Estruturas Condicionais
if / else
Sintaxe:
if (condicao) {
// Código executado se a condição for verdadeira
} else {
// Código executado se a condição for falsa
}
Exemplo:
val numero = 10
if (numero > 0) {
println("O número é positivo")
} else {
println("O número é negativo ou zero")
}
O if
também pode ser usado como expressão retornando um valor:
val resultado = if (numero % 2 == 0) "Par" else "Ímpar"
println(resultado)
when
O when
substitui o switch
de outras linguagens e permite comparar um valor com múltiplas condições.
Sintaxe:
when (variavel) {
valor1 -> { // Código }
valor2 -> { // Código }
else -> { // Código }
}
Exemplo:
val dia = 3
val nomeDoDia = when (dia) {
1 -> "Domingo"
2 -> "Segunda-feira"
3 -> "Terça-feira"
4 -> "Quarta-feira"
5 -> "Quinta-feira"
6 -> "Sexta-feira"
7 -> "Sábado"
else -> "Dia inválido"
}
println(nomeDoDia)
O when
também pode ser usado com expressões mais complexas:
val idade = 25
when {
idade < 12 -> println("Criança")
idade in 12..17 -> println("Adolescente")
else -> println("Adulto")
}
Estruturas de Repetição
while
Sintaxe:
while (condicao) {
// Código executado repetidamente
}
Exemplo:
var contador = 1
while (contador <= 5) {
println("Contador: $contador")
contador++
}
do-while
O do-while
executa pelo menos uma vez, pois a verificação da condição ocorre após a execução do bloco.
Sintaxe:
do {
// Código executado ao menos uma vez
} while (condicao)
Exemplo:
var numero = 0
do {
println("Número: $numero")
numero++
} while (numero < 3)
for
O for
é usado para iterar sobre intervalos, listas e outras coleções.
Sintaxe:
for (item in colecao) {
// Código executado para cada item
}
Exemplo com intervalos:
for (i in 1..5) {
println("Número: $i")
}
Exemplo com listas:
val frutas = listOf("Maçã", "Banana", "Laranja")
for (fruta in frutas) {
println(fruta)
}
Exemplo com índice:
val nomes = listOf("Ana", "Bruno", "Carlos")
for ((indice, nome) in nomes.withIndex()) {
println("$indice: $nome")
}
Controle de Loop: break e continue
break
: interrompe o loop completamente.continue
: pula para a próxima iteração do loop.
Exemplo:
for (i in 1..10) {
if (i == 5) break
println(i)
}
Saída:
1
2
3
4
for (i in 1..10) {
if (i % 2 == 0) continue
println(i)
}
Saída:
1
3
5
7
9
Funções em Kotlin
As funções são blocos de código reutilizáveis que executam uma tarefa específica. No Kotlin, as funções podem ter parâmetros, retornar valores e até serem funções de alta ordem.
Declaração de Funções
A palavra-chave fun
é usada para declarar uma função em Kotlin.
Sintaxe básica:
fun nomeDaFuncao(parametros): TipoDeRetorno {
// Corpo da função
return valor
}
Exemplo:
fun soma(a: Int, b: Int): Int {
return a + b
}
val resultado = soma(3, 5)
println(resultado) // Saída: 8
Funções com Retorno Unit
Se uma função não retorna um valor, seu tipo de retorno é Unit
(equivalente a void
em outras linguagens). O Unit
pode ser omitido.
fun imprimirMensagem(mensagem: String): Unit {
println(mensagem)
}
imprimirMensagem("Olá, Kotlin!")
Funções de Uma Linha (Expressões)
Se a função consiste em apenas uma expressão, podemos usar a sintaxe simplificada:
fun multiplicar(a: Int, b: Int) = a * b
println(multiplicar(4, 3)) // Saída: 12
Parâmetros com Valores Padrão
Podemos definir valores padrão para parâmetros:
fun saudar(nome: String = "Visitante") {
println("Olá, $nome!")
}
saudar() // Saída: Olá, Visitante!
saudar("Carlos") // Saída: Olá, Carlos!
Parâmetros Nomeados
Podemos chamar funções especificando os nomes dos parâmetros para maior clareza:
fun formatarTexto(texto: String, repetir: Int = 1, maiusculo: Boolean = false) {
val resultado = if (maiusculo) texto.uppercase() else texto
repeat(repetir) { println(resultado) }
}
formatarTexto(repetir = 3, texto = "Oi", maiusculo = true)
Funções de Extensão
No Kotlin, podemos adicionar novas funções a classes existentes sem modificá-las, usando funções de extensão.
fun String.reverter(): String {
return this.reversed()
}
println("Kotlin".reverter()) // Saída: niltoK
Funções Lambda (Funções Anônimas)
Kotlin permite definir funções anônimas (lambdas) que podem ser atribuídas a variáveis ou passadas como argumentos.
val soma = { a: Int, b: Int -> a + b }
println(soma(5, 7)) // Saída: 12
Funções de Alta Ordem
Funções que recebem outras funções como parâmetro ou retornam funções são chamadas de alta ordem.
fun operacao(a: Int, b: Int, funcao: (Int, Int) -> Int): Int {
return funcao(a, b)
}
val resultadoSoma = operacao(10, 20, ::soma)
println(resultadoSoma) // Saída: 30
No exemplo acima, usamos ::soma
para referenciar diretamente a função soma
. O operador ::
é usado para obter uma referência de função, permitindo que a função seja passada como argumento sem ser executada imediatamente.
Trailing Lambdas
Quando o último (ou único) parâmetro de uma função é uma função lambda, podemos movê-la para fora dos parênteses, tornando o código mais legível. Esse recurso é chamado de trailing lambda.
Exemplo sem trailing lambda:
fun executar(acao: () -> Unit) {
acao()
}
executar({ println("Executando ação!") })
Exemplo com trailing lambda:
executar {
println("Executando ação!")
}
Esse estilo é amplamente utilizado em bibliotecas Kotlin, como nas funções forEach
de listas:
val numeros = listOf(1, 2, 3, 4)
numeros.forEach {
println(it)
}
Coleções em Kotlin
As coleções em Kotlin são estruturas de dados que armazenam múltiplos elementos. Existem três tipos principais de coleções:
- List: Uma coleção ordenada de elementos.
- Set: Uma coleção de elementos únicos.
- Map: Uma coleção de pares chave-valor.
Listas (List)
Uma List
é uma coleção ordenada de elementos, que pode ser mutável ou imutável.
Lista imutável (List)
val listaImutavel = listOf("Maçã", "Banana", "Laranja")
println(listaImutavel[0]) // Saída: Maçã
Lista mutável (MutableList)
val listaMutavel = mutableListOf("Maçã", "Banana")
listaMutavel.add("Laranja")
println(listaMutavel) // Saída: [Maçã, Banana, Laranja]
Operações comuns com List
val numeros = listOf(1, 2, 3, 4, 5)
println(numeros.size) // Obtém o tamanho da lista
println(numeros.contains(3)) // Verifica se um elemento existe
println(numeros.first()) // Primeiro elemento
println(numeros.last()) // Último elemento
Conjuntos (Set)
Os conjuntos (Set
) armazenam elementos únicos e não garantem uma ordem específica.
Set imutável
val setImutavel = setOf(1, 2, 3, 3)
println(setImutavel) // Saída: [1, 2, 3]
Set mutável
val setMutavel = mutableSetOf(1, 2, 3)
setMutavel.add(4)
setMutavel.add(2) // Elemento duplicado não é adicionado
println(setMutavel) // Saída: [1, 2, 3, 4]
Mapas (Map)
Os mapas (Map
) armazenam pares chave-valor.
Map imutável
val mapaImutavel = mapOf("nome" to "Carlos", "idade" to 30)
println(mapaImutavel["nome"]) // Saída: Carlos
Map mutável
val mapaMutavel = mutableMapOf("nome" to "Ana")
mapaMutavel["idade"] = 25
println(mapaMutavel) // Saída: {nome=Ana, idade=25}
Operações com Map
val mapa = mapOf(1 to "um", 2 to "dois", 3 to "três")
println(mapa.keys) // Obtém as chaves
println(mapa.values) // Obtém os valores
println(mapa.containsKey(2)) // Verifica se a chave existe
Iteração sobre Coleções
Iterando com for
val lista = listOf("A", "B", "C")
for (item in lista) {
println(item)
}
Usando forEach
lista.forEach { println(it) }
Filtragem e Transformação
Filtragem (filter
)
val numeros = listOf(1, 2, 3, 4, 5)
val pares = numeros.filter { it % 2 == 0 }
println(pares) // Saída: [2, 4]
Transformação (map
)
val dobrado = numeros.map { it * 2 }
println(dobrado) // Saída: [2, 4, 6, 8, 10]
Orientação a Objetos em Kotlin
A Orientação a Objetos (OO) é um paradigma de programação que organiza o código em torno de objetos. No Kotlin, podemos trabalhar com classes, herança, encapsulamento, polimorfismo e interfaces de forma simples e intuitiva.
Classes e Objetos
Uma classe é um modelo para criar objetos. Em Kotlin, usamos a palavra-chave class
para definir classes.
Exemplo de classe e objeto:
class Pessoa(val nome: String, var idade: Int) {
fun saudacao() {
println("Olá, meu nome é $nome e tenho $idade anos.")
}
}
val pessoa = Pessoa("Carlos", 30)
pessoa.saudacao() // Saída: Olá, meu nome é Carlos e tenho 30 anos.
Construtores
Podemos definir construtores primários diretamente na declaração da classe e construtores secundários dentro do corpo da classe.
Construtor primário:
class Carro(val marca: String, val modelo: String)
val carro = Carro("Toyota", "Corolla")
println(carro.marca) // Saída: Toyota
Construtor secundário:
class Animal {
var nome: String
var especie: String
constructor(nome: String, especie: String) {
this.nome = nome
this.especie = especie
}
}
val cachorro = Animal("Rex", "Cachorro")
println(cachorro.nome) // Saída: Rex
Herança
Kotlin permite herança entre classes usando open
para permitir que uma classe seja estendida.
open class Animal(val nome: String) {
open fun fazerSom() {
println("Som genérico")
}
}
class Cachorro(nome: String) : Animal(nome) {
override fun fazerSom() {
println("Au Au")
}
}
val cachorro = Cachorro("Bolt")
cachorro.fazerSom() // Saída: Au Au
Modificadores de Visibilidade
Kotlin oferece quatro modificadores de visibilidade:
public
(padrão) – acessível de qualquer lugar.private
– acessível apenas dentro da classe.protected
– acessível dentro da classe e subclasses.internal
– acessível dentro do mesmo módulo.
class ContaBancaria(private val saldo: Double) {
fun exibirSaldo() {
println("Saldo: $saldo")
}
}
val conta = ContaBancaria(1000.0)
conta.exibirSaldo() // Saída: Saldo: 1000.0
Classes Abstratas
Classes abstratas não podem ser instanciadas diretamente e servem como modelo para subclasses.
abstract class SerVivo(val nome: String) {
abstract fun mover()
}
class Peixe(nome: String) : SerVivo(nome) {
override fun mover() {
println("O peixe está nadando")
}
}
val peixe = Peixe("Nemo")
peixe.mover() // Saída: O peixe está nadando
Interfaces
Interfaces definem comportamentos que podem ser implementados por várias classes.
interface Nadador {
fun nadar() {
println("Estou nadando!")
}
}
class Golfinho : Nadador
val golfinho = Golfinho()
golfinho.nadar() // Saída: Estou nadando!
Data Classes
As data class
são usadas para armazenar dados de forma eficiente, gerando automaticamente métodos como toString()
, equals()
, e copy()
.
data class Usuario(val nome: String, val idade: Int)
val usuario1 = Usuario("Ana", 25)
val usuario2 = usuario1.copy(idade = 30)
println(usuario1) // Saída: Usuario(nome=Ana, idade=25)
println(usuario2) // Saída: Usuario(nome=Ana, idade=30)
Exercícios Práticos para entregar
https://gitlab.com/ds151-alexkutzke/ds151-kotlin-assignment