DEV Community

Cover image for Estruturas de controle em Kotlin
Ronaldo Costa de Freitas
Ronaldo Costa de Freitas

Posted on • Updated on

Estruturas de controle em Kotlin

Kotlin, assim como outras linguagens de programação de alto nível, tem estruturas de controle básicas como while, for e if. No post de hoje vamos conhecê-las e aprender sobre a estrutura substituta do switch, o when.

Estrutura while

Essa estrutura de controle é bem similar ao Java, sendo praticamente idêntica. Além de while, também temos sua irmã, a estrutura do-while. Como são muito parecidas com as em Java, vamos analisar brevemente dois códigos sobre elas.

A estrutura while tem o seguinte formato:

fun main() {
    var palavra = ""

    while(palavra.length <= 10) {
        palavra += 'z'
    }
}
Enter fullscreen mode Exit fullscreen mode

Ou seja, o programa irá executar repetidamente uma ou mais linhas de código enquanto uma condição for atendida. No caso acima, o loop irá ocorrer até que o tamanho da string seja menor ou igual a 10, o loop irá cessar quando a palavra alcançar o tamanho 11.

Por outro lado, a estrutura do-while tem o seguinte formato:

fun main() {
    var palavra = ""

    do {
        palavra += 'z'
    } while(palavra.length != 0)
}
Enter fullscreen mode Exit fullscreen mode

Enquanto na estrutura while, não temos a garantia de que o loop será executado, na do-while sabemos que ele ocorre ao menos uma vez. Como podemos ver acima, primeiro incrementamos a palavra em um caractere e depois comparamos se seu tamanho é diferente de zero, o que ocasiona em um loop infinito, visto que seu tamanho sempre será diferente de zero. No entanto, se usássemos while, isso não teria ocorrido, já que a comparação teria sido feita antes do incremento.

Estrutura for

Diferentemente de while e do-while, a estrutura de controle for em Kotlin é diferente da em Java e tem várias formas de uso específico, como iterar sobre um intervalo ou uma coleção.

Iterando sobre intervalos

Se quisermos imprimir todos os números naturais (incluindo o zero) até um certo outro número natural, excluindo ele mesmo, como podemos fazer em Kotlin? Podemos usar o operador .. entre zero e o determinado número menos 1. Esse operador indica que estamos usando um intervalo entre dois valores:

import kotlin.random.Random

fun main() {
    val numeroRandom = Random.nextInt(0, 100)

    for(i in 0 .. numeroRandom-1) {
        println(i)
    }
}
Enter fullscreen mode Exit fullscreen mode

No código acima, primeiro obtemos um número pseudo-randômico entre 0 e 100 e depois usamos for com o operador .. pra indicar que iremos iterar sobre esse intervalo, além de utilizarmos o operador in que garante que o valor de i esteja no intervalo especificado. Podemos deixar esse código mais idiomático usando a função until, que simula esse comportamento de 0 (intervalo) valor - 1:

import kotlin.random.Random

fun main() {
    val numeroRandom = Random.nextInt(0, 100)

    for(i in 0 until numeroRandom) {
        println(i)
    }
}
Enter fullscreen mode Exit fullscreen mode

Também podemos iterar sobre intervalos utilizando outros funções como downTo e step. Se queremos imprimir todos os número pares entre 100 e 0, podemos fazer o seguinte:

fun main() {

    for(i in 100 downTo 0 step 2) {
        println(i)
    }
}
Enter fullscreen mode Exit fullscreen mode

A função downTo indica que o intervalo é de trás para frente e a função step faz com que dois números sejam pulados a cada iteração, assim, imprimindo apenas os números pares. Essa função está presente em todos esses fors que envolvem intervalo, quando não a utilizamos explicitamente ela tem o comportamento padrão de pular um número de cada vez, ou seja step 1.

Iterando sobre coleções

Assim como em Java, também podemos iterar sobre coleções (estruturas de dados de alto nível) em Kotlin, fazendo um trabalho semelhante ao forEach(). Vamos fazer um programa que adiciona os quadrados dos números de uma lista de inteiros em outra:

fun main() {

  val numeros = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  val numerosQuadrados = mutableListOf<Int>()

  for(numero in numeros)
      numerosQuadrados.add(numero * numero)

  println(numerosQuadrados)
}
Enter fullscreen mode Exit fullscreen mode

Note que também usamos o operador in para iterar sobre a lista, basicamente desempacotando cada número da lista em uma variável chamada numero. Também podemos usar o in para iterar sobre caracteres:

fun main() {

    val palavra = "Palavra"
    var palavraEmMaiusculas = ""

    for(letra in palavra) {
        palavraEmMaiusculas += letra.toUpperCase()
    }

    println(palavraEmMaiusculas)
}
Enter fullscreen mode Exit fullscreen mode

No código acima, nós iteramos sobre uma string e adicionamos cada caractere dela como uma letra maiúscula em outra string.

Estrutura if

De forma semelhante a while, a estrutura de controla if é praticamente idêntica a sua equivalente em Java, o que muda aqui é, conforme estudamos no último post, em Kotlin if não é um statement, mas sim uma expressão, ou seja, ela tem um retorno. Vamos analisar a função abaixo:

fun ePar(numero: Int): Boolean {
    return if(numero % 2 == 0) {
        true
    } else {
        false
    }
}
Enter fullscreen mode Exit fullscreen mode

O que fazemos aqui é retorna o resultado da expressão if que compara se um número inteiro, quando divido por 2, deixa resto zero. Também podemos fazer uma estrutura if aninhada em Kotlin, usando else if:

fun compara(A: Int, B: Int): String {
    return if(A > B) {
        "$A é maior que $B"
    } else if(A < B) {
        "$A é menor que $B"
    } else {
        "$A e $B são iguais"
    }
}
Enter fullscreen mode Exit fullscreen mode

Estrutura when

A estrutura when é uma substituta para o if em alguns casos, ela funciona como um switch em Java e assim como o if ela pode ter ramificações e retornar valores. Vamos reescrever os dois últimos códigos usando when:

fun eParWhen(numero: Int) =
    when {
        numero % 2 == 0 -> {
            true
        }
        else -> false
    }

fun comparaWhen(A: Int, B: Int) =
    when {
        A > B -> "$A é maior que $B"
        A < B -> "$A é menor que $B"
        else -> "$A e $B são iguais"
    }
Enter fullscreen mode Exit fullscreen mode

A estrutura when é muito útil para se lidar com Enums, vamos analisar um exemplo do Kotlin in Action. Primeiro vamos criar a enum Color que irá representar cores no formato RGB:

enum class Color(
    val red: Int, val green: Int, val blue: Int
) {
    RED(255, 0, 0), ORANGE(255, 165, 0), YELLOW(255, 255, 0), GREEN(0, 255, 0),
    BLUE(0, 0, 255), INDIGO(75, 0, 130), VIOLET(238, 130, 238), WHITE(255, 255, 255);

    fun rgb() = (red * 256 + green) * 256 + blue
}
Enter fullscreen mode Exit fullscreen mode

Como pode ver, além de constantes, uma enum em Kotlin pode ter propriedades e funções, em adição a isso esse exemplo também mostra o único caso de uso de ponto e vírgula em Kotlin: para separar as constantes de uma enum das suas funções.

As constantes que foram definidas representam certas cores para certos valores das três propriedades e a função rgb() retorna a ordem dessa cor na gama de cores que podem ser representadas no formato RGB.

Por exemplo, se usarmos essa função para a cor BLUE, veremos que ela é a cor de número 255, agora se usarmos para a cor WHITE, podemos observar que ela é a cor de número 16777215, ou seja, a última cor, já que podem ser representadas pouco mais de 16 milhões de cores em RGB.

Agora vamos usar when para facilitar a nossa vida: caso precisássemos fazer uma função que retorna a "temperatura” de um certa cor, como faríamos ser usar vários ifs? Simples:

fun obtemTemperaturaCor(color: Color) =
    when(color) {
            Color.RED, Color.ORANGE, Color.YELLOW -> "Quente"
            Color.GREEN -> "Neutra"
            Color.BLUE, Color.INDIGO, Color.INDIGO, Color.VIOLET, Color.WHITE -> "Fria" 
    }
Enter fullscreen mode Exit fullscreen mode

Veja só que beleza: podemos até combinar múltiplos valores em uma única ramificação, não é incrível 🤩?

Sendo assim, podemos observar que a forma dessa estrutura é a seguinte:

when (valorOpcional) {
    condicao1 -> {
        // faz alguma coisa
    }
    condicao2 -> {
        //faz outra coisa
    }
    else -> { // else opcional
        // faz algo
    }
}
Enter fullscreen mode Exit fullscreen mode

Diferentemente do switch, não somos obrigados a passar o valor que será comparado entre parênteses e nem escrever declarações break ao fim de cada ramificação.

Próximos posts

Nos próximos posts vamos nos aprofundar no estudo de funções e estudar classes, objetos e interfaces. Obrigado pela atenção, até a próxima!

Post anterior:

Próximo post:

Top comments (0)