1. Antes de começar
Agora que você já aprendeu o básico da programação Kotlin, está na hora de colocar em prática.
Estes exercícios testam a compreensão dos conceitos que você estudou. Eles são baseados em casos reais e você, como usuário, provavelmente já viu alguns deles.
Siga as instruções e encontre uma solução para cada exercício no Playground Kotlin. Se tiver dificuldades, alguns dos exercícios têm dicas que podem ajudar. O código da solução para cada exercício está no final, mas a ideia é que você resolva os exercícios antes de ver as respostas.
Faça os exercícios em um ritmo confortável. Há estimativas de duração para os exercícios, mas você não precisa se apegar a elas. Leve o tempo que precisar para resolver cada problema com atenção. As soluções mostram apenas uma maneira de resolver os exercícios; então, fique à vontade para fazer experiências como quiser.
Pré-requisitos
- Conhecer o Playground Kotlin.
- Saber definir e chamar funções.
- Conhecimentos básicos de programação em Kotlin, incluindo variáveis e as funções
println()
emain()
. - Familiaridade com condicionais do Kotlin, incluindo expressões e instruções
if/else
ewhen
. - Familiaridade com expressões lambda do Kotlin
- Saber processar variáveis anuláveis.
- Saber criar classes e objetos do Kotlin.
- Já ter feito os codelabs Escrever condicionais em Kotlin, Usar a nulidade no Kotlin, Usar classes e objetos no Kotlin e Usar tipos de função e expressões lambda no Kotlin.
O que é necessário
- Playground Kotlin
2. Notificações no dispositivo móvel
Normalmente, o smartphone oferece um resumo das notificações.
No código inicial fornecido no snippet abaixo, escreva um programa que mostra a mensagem de resumo com base no número de notificações recebidas. A mensagem precisa incluir:
- O número exato de notificações quando menor que 100.
99+
como o número de notificações quando houver 100 ou mais.
fun main() {
val morningNotification = 51
val eveningNotification = 135
printNotificationSummary(morningNotification)
printNotificationSummary(eveningNotification)
}
fun printNotificationSummary(numberOfMessages: Int) {
// Fill in the code.
}
Complete a função printNotificationSummary()
para que o programa mostre estas linhas:
You have 51 notifications. Your phone is blowing up! You have 99+ notifications.
3. Preço do ingresso do cinema
Geralmente, o preço dos ingressos é diferente dependendo da idade dos usuários.
No código inicial fornecido no snippet abaixo, escreva um programa que calcule estes preços de ingressos com base na idade:
- O preço do ingresso é US$ 15 para pessoas de até 12 anos.
- O preço padrão do ingresso é US$ 30 para pessoas com idade entre 13 e 60 anos. Às segundas-feiras, você pode aplicar um desconto para que o ingresso padrão dessa faixa etária custe US$ 25.
- O preço de US$ 20 do ingresso para idosos é válido para pessoas com 61 anos ou mais. Suponha que a idade máxima de um frequentador de cinema seja de 100 anos.
- Um valor
-1
indica que o preço é inválido quando um usuário inserir uma idade fora das especificações.
fun main() {
val child = 5
val adult = 28
val senior = 87
val isMonday = true
println("The movie ticket price for a person aged $child is \$${ticketPrice(child, isMonday)}.")
println("The movie ticket price for a person aged $adult is \$${ticketPrice(adult, isMonday)}.")
println("The movie ticket price for a person aged $senior is \$${ticketPrice(senior, isMonday)}.")
}
fun ticketPrice(age: Int, isMonday: Boolean): Int {
// Fill in the code.
}
Complete a função ticketPrice()
para que o programa mostre estas linhas:
The movie ticket price for a person aged 5 is $15. The movie ticket price for a person aged 28 is $25. The movie ticket price for a person aged 87 is $20.
4. Conversor de temperatura
Existem três padrões principais de temperatura usados no mundo: Celsius, Fahrenheit e Kelvin.
No código inicial fornecido no snippet abaixo, escreva um programa que converta uma temperatura de um padrão a outro usando estas fórmulas:
- Celsius para Fahrenheit: °F = 9/5 (°C) + 32
- Kelvin para Celsius: °C = K - 273,15
- Fahrenheit para Kelvin: K = 5/9 (°F - 32) + 273,15
O método String.format("%.2f", /* measurement */ )
é usado para converter um número em um tipo String
com duas casas decimais.
fun main() {
// Fill in the code.
}
fun printFinalTemperature(
initialMeasurement: Double,
initialUnit: String,
finalUnit: String,
conversionFormula: (Double) -> Double
) {
val finalMeasurement = String.format("%.2f", conversionFormula(initialMeasurement)) // two decimal places
println("$initialMeasurement degrees $initialUnit is $finalMeasurement degrees $finalUnit.")
}
Complete a função main()
para chamar a função printFinalTemperature()
e mostrar as linhas abaixo. É necessário transmitir argumentos para a fórmula de conversão e a temperatura. Dica: use valores Double
para evitar truncamentos de números Integer
durante as operações de divisão.
27.0 degrees Celsius is 80.60 degrees Fahrenheit. 350.0 degrees Kelvin is 76.85 degrees Celsius. 10.0 degrees Fahrenheit is 260.93 degrees Kelvin.
5. Catálogo de músicas
Imagine que você precise criar um app de reprodução de música.
Crie uma classe que represente a estrutura de uma música. A classe Song
precisa incluir estes elementos de código:
- Propriedades do título, artista, ano de lançamento e contagem de reprodução.
- Uma propriedade que indica se a música é famosa. Se a contagem de reprodução for menor que 1.000, considere que não é famosa.
- Um método que mostra uma descrição de música neste formato:
"[Título], de [artista], lançado em [ano de lançamento]."
6. Perfil da Internet
Muitas vezes, é necessário preencher perfis para sites on-line que contêm campos obrigatórios e não obrigatórios. Por exemplo, você pode adicionar suas informações pessoais e enviar um link para as pessoas que indicaram que você criasse o perfil.
No código inicial fornecido no snippet abaixo, escreva um programa que mostre os detalhes do perfil de uma pessoa.
fun main() {
val amanda = Person("Amanda", 33, "play tennis", null)
val atiqah = Person("Atiqah", 28, "climb", amanda)
amanda.showProfile()
atiqah.showProfile()
}
class Person(val name: String, val age: Int, val hobby: String?, val referrer: Person?) {
fun showProfile() {
// Fill in code
}
}
Complete a função showProfile()
para que o programa mostre estas linhas:
Name: Amanda Age: 33 Likes to play tennis. Doesn't have a referrer. Name: Atiqah Age: 28 Likes to climb. Has a referrer named Amanda, who likes to play tennis.
7. Smartphones dobráveis
Normalmente, pressionar o botão liga/desliga do smartphone ativa ou desativa a tela dele. Por outro lado, se um smartphone dobrável estiver dobrado, a tela interna principal dele não vai ser ativada quando o botão liga/desliga for pressionado.
No código inicial fornecido no snippet abaixo, escreva uma classe FoldablePhone
herdada da classe Phone
. Ela vai conter o seguinte:
- Uma propriedade que indica se o smartphone está dobrado.
- Um comportamento da função
switchOn()
diferente da classePhone
para que ela só ative a tela quando o telefone não estiver dobrado. - Métodos para mudar o estado da dobra.
class Phone(var isScreenLightOn: Boolean = false){
fun switchOn() {
isScreenLightOn = true
}
fun switchOff() {
isScreenLightOn = false
}
fun checkPhoneScreenLight() {
val phoneScreenLight = if (isScreenLightOn) "on" else "off"
println("The phone screen's light is $phoneScreenLight.")
}
}
8. Leilão especial
Normalmente, em um leilão, o maior lance determina o preço de um item. Nesse leilão especial, se não houver um lance para um item, ele vai ser vendido automaticamente para o sistema de leilão pelo preço mínimo.
No código inicial fornecido no snippet abaixo, você tem uma função auctionPrice()
que aceita um tipo Bid?
anulável como argumento:
fun main() {
val winningBid = Bid(5000, "Private Collector")
println("Item A is sold at ${auctionPrice(winningBid, 2000)}.")
println("Item B is sold at ${auctionPrice(null, 3000)}.")
}
class Bid(val amount: Int, val bidder: String)
fun auctionPrice(bid: Bid?, minimumPrice: Int): Int {
// Fill in the code.
}
Complete a função auctionPrice()
para que o programa mostre estas linhas:
Item A is sold at 5000. Item B is sold at 3000.
9. Código da solução
Notificações no dispositivo móvel
A solução usa uma instrução if/else
para mostrar a mensagem correta com base no número de notificações recebidas:
fun main() {
val morningNotification = 51
val eveningNotification = 135
printNotificationSummary(morningNotification)
printNotificationSummary(eveningNotification)
}
fun printNotificationSummary(numberOfMessages: Int) {
if (numberOfMessages < 100) {
println("You have ${numberOfMessages} notifications.")
} else {
println("Your phone is blowing up! You have 99+ notifications.")
}
}
Preço do ingresso do cinema
A solução usa uma expressão when
para retornar o preço correto do ingresso com base na idade do espectador. Ela também usa uma expressão if/else
simples para uma das ramificações da expressão when
para adicionar a condição extra ao preço padrão do ingresso.
O preço do ingresso na ramificação else
retorna um valor -1
, que indica que o conjunto de preços é inválido para a ramificação else
. Uma implementação melhor é que a ramificação else
gere uma exceção. Você vai aprender sobre o gerenciamento de exceções nas próximas unidades.
fun main() {
val child = 5
val adult = 28
val senior = 87
val isMonday = true
println("The movie ticket price for a person aged $child is \$${ticketPrice(child, isMonday)}.")
println("The movie ticket price for a person aged $adult is \$${ticketPrice(adult, isMonday)}.")
println("The movie ticket price for a person aged $senior is \$${ticketPrice(senior, isMonday)}.")
}
fun ticketPrice(age: Int, isMonday: Boolean): Int {
return when(age) {
in 0..12 -> 15
in 13..60 -> if (isMonday) 25 else 30
in 61..100 -> 20
else -> -1
}
}
Conversor de temperatura
A solução exige que você transmita uma função como um parâmetro para a função printFinalTemperature()
. A solução mais sucinta transmite expressões lambda como argumentos, usa a referência de parâmetro it
no lugar dos nomes dos parâmetros e usa a sintaxe da lambda final.
fun main() {
printFinalTemperature(27.0, "Celsius", "Fahrenheit") { 9.0 / 5.0 * it + 32 }
printFinalTemperature(350.0, "Kelvin", "Celsius") { it - 273.15 }
printFinalTemperature(10.0, "Fahrenheit", "Kelvin") { 5.0 / 9.0 * (it - 32) + 273.15 }
}
fun printFinalTemperature(
initialMeasurement: Double,
initialUnit: String,
finalUnit: String,
conversionFormula: (Double) -> Double
) {
val finalMeasurement = String.format("%.2f", conversionFormula(initialMeasurement)) // two decimal places
println("$initialMeasurement degrees $initialUnit is $finalMeasurement degrees $finalUnit.")
}
Catálogo de músicas
A solução contém uma classe Song
com um construtor padrão que aceita todos os parâmetros necessários. A classe Song
também tem uma propriedade isPopular
que usa uma função getter personalizada e um método que mostra a descrição em si. É possível criar uma instância da classe na função main()
e chamar os métodos dela para testar se a implementação está correta. É possível usar sublinhados ao escrever números grandes, como o valor 1_000_000
, para torná-lo mais legível.
fun main() {
val brunoSong = Song("We Don't Talk About Bruno", "Encanto Cast", 2022, 1_000_000)
brunoSong.printDescription()
println(brunoSong.isPopular)
}
class Song(
val title: String,
val artist: String,
val yearPublished: Int,
val playCount: Int
){
val isPopular: Boolean
get() = playCount >= 1000
fun printDescription() {
println("$title, performed by $artist, was released in $yearPublished.")
}
}
Quando você chama a função println()
nos métodos da instância, o programa pode mostrar esta saída:
We Don't Talk About Bruno, performed by Encanto Cast, was released in 2022. true
Perfil da Internet
A solução contém verificações de valores nulos em várias instruções if/else
para mostrar um texto diferente se várias propriedades tiverem um valor null
:
fun main() {
val amanda = Person("Amanda", 33, "play tennis", null)
val atiqah = Person("Atiqah", 28, "climb", amanda)
amanda.showProfile()
atiqah.showProfile()
}
class Person(val name: String, val age: Int, val hobby: String?, val referrer: Person?) {
fun showProfile() {
println("Name: $name")
println("Age: $age")
if(hobby != null) {
print("Likes to $hobby. ")
}
if(referrer != null) {
print("Has a referrer named ${referrer.name}")
if(referrer.hobby != null) {
print(", who likes to ${referrer.hobby}.")
} else {
print(".")
}
} else {
print("Doesn't have a referrer.")
}
print("\n\n")
}
}
Smartphones dobráveis
Para que a classe Phone
seja mãe, é necessário torná-la aberta adicionando a palavra-chave open
antes do nome dela. Para substituir o método switchOn()
na classe FoldablePhone
, é necessário tornar o método na classe Phone
aberto adicionando a palavra-chave open
antes dele.
A solução contém uma classe FoldablePhone
com um construtor padrão que tem um argumento padrão para o parâmetro isFolded
. A classe FoldablePhone
também tem dois métodos para mudar a propriedade isFolded
para um valor true
ou false
. Ela também substitui o método switchOn()
herdado da classe Phone
.
É possível criar uma instância da classe na função main()
e chamar os métodos para testar se a implementação está correta.
open class Phone(var isScreenLightOn: Boolean = false){
open fun switchOn() {
isScreenLightOn = true
}
fun switchOff() {
isScreenLightOn = false
}
fun checkPhoneScreenLight() {
val phoneScreenLight = if (isScreenLightOn) "on" else "off"
println("The phone screen's light is $phoneScreenLight.")
}
}
class FoldablePhone(var isFolded: Boolean = true): Phone() {
override fun switchOn() {
if (!isFolded) {
isScreenLightOn = true
}
}
fun fold() {
isFolded = true
}
fun unfold() {
isFolded = false
}
}
fun main() {
val newFoldablePhone = FoldablePhone()
newFoldablePhone.switchOn()
newFoldablePhone.checkPhoneScreenLight()
newFoldablePhone.unfold()
newFoldablePhone.switchOn()
newFoldablePhone.checkPhoneScreenLight()
}
A saída é esta:
The phone screen's light is off. The phone screen's light is on.
Leilão especial
A solução usa o operador de chamada segura ?.
e o operador Elvis ?:
para retornar o preço correto:
fun main() {
val winningBid = Bid(5000, "Private Collector")
println("Item A is sold at ${auctionPrice(winningBid, 2000)}.")
println("Item B is sold at ${auctionPrice(null, 3000)}.")
}
class Bid(val amount: Int, val bidder: String)
fun auctionPrice(bid: Bid?, minimumPrice: Int): Int {
return bid?.amount ?: minimumPrice
}
10. Mais exercícios
Para praticar mais sobre a linguagem Kotlin, confira a faixa principal de Kotlin da JetBrains Academy. Para ir a um tópico específico, acesse o mapa de conhecimento (links em inglês) e confira a lista de temas abordados na faixa.