1. Avant de commencer
Maintenant que vous avez travaillé dur pour apprendre les bases de la programmation Kotlin, il est temps de mettre vos connaissances en pratique.
Ces exercices testeront votre compréhension des concepts que vous avez étudiés. Ils sont basés sur des cas d'utilisation concrets. Il est d'ailleurs probable que vous en ayez déjà expérimenté quelques-uns auparavant en tant qu'utilisateur.
Pour trouver une solution à chaque exercice dans Kotlin Playground, suivez les instructions. Si vous êtes bloqué, certains exercices incluent des conseils pour vous aider. Le code de solution est disponible à la fin de chaque exercice, mais nous vous recommandons d'essayer de résoudre les exercices par vous-même avant de vérifier la solution.
Réalisez ces exercices à votre rythme. L'estimation de leur durée est uniquement fournie à titre de référence. Ne suivez pas ces estimations à la lettre. Prenez le temps de résoudre chaque problème de manière réfléchie. Les solutions ne représentent qu'une manière de résoudre les exercices. N'hésitez pas à tester des approches différentes si vous le souhaitez.
Conditions préalables
- Vous connaissez Kotlin Playground.
- Vous êtes capable de définir et d'appeler des fonctions.
- Vous connaissez les bases de la programmation Kotlin, y compris les variables, et les fonctions
println()
etmain()
. - Vous maîtrisez les conditions Kotlin, y compris les expressions et les instructions
if/else
etwhen
. - Vous maîtrisez les expressions lambda de Kotlin.
- Vous savez comment gérer les variables pouvant avoir une valeur nulle.
- Vous savez comment créer des classes et des objets Kotlin.
- Vous avez mené à bien les ateliers de programmation Écrire des instructions conditionnelles en langage Kotlin, Utiliser la possibilité de valeur nulle en Kotlin, Utiliser les classes et les objets en Kotlin et Utiliser les types de fonctions et les expressions lambda en Kotlin.
Ce dont vous avez besoin
- Kotlin Playground
2. Notifications mobiles
En général, vous recevez un récapitulatif des notifications sur votre téléphone.
Dans le code initial fourni dans l'extrait de code suivant, rédigez un programme qui imprimera le message récapitulatif en fonction du nombre de notifications que vous avez reçues. Ce message devra inclure les éléments suivants :
- Nombre exact de notifications lorsqu'il ne dépasse pas 100 notifications
99+
pour le nombre de notifications lorsqu'il y en a plus de 100
fun main() {
val morningNotification = 51
val eveningNotification = 135
printNotificationSummary(morningNotification)
printNotificationSummary(eveningNotification)
}
fun printNotificationSummary(numberOfMessages: Int) {
// Fill in the code.
}
Exécutez la fonction printNotificationSummary()
pour que le programme imprime les lignes suivantes :
You have 51 notifications. Your phone is blowing up! You have 99+ notifications.
3. Prix du billet de cinéma
Les places de cinéma sont généralement facturées différemment selon l'âge des spectateurs.
Dans le code initial fourni dans l'extrait de code suivant, rédigez un programme qui calculera le prix des billets en fonction de l'âge :
- Un billet enfant de 15 $ pour les personnes âgées de 12 ans et moins.
- Un prix standard de 30 $ par billet pour les personnes âgées de 13 à 60 ans. Le lundi, faites passer le prix du billet standard à 25 $ pour cette tranche d'âge.
- Un billet senior de 20 $ pour les personnes âgées de 61 ans et plus. Nous supposerons que l'âge maximal d'un spectateur est de 100 ans.
- Une valeur
-1
pour indiquer que le prix n'est pas valable lorsqu'un utilisateur saisit une tranche d'âge qui ne correspond pas à celles spécifié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.
}
Exécutez la fonction ticketPrice()
pour que le programme imprime les lignes suivantes :
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. Convertisseur de température
Il existe trois échelles de température principales : les degrés Celsius, les degrés Fahrenheit et le kelvin.
Dans le code initial fourni dans l'extrait de code suivant, rédigez un programme qui convertira la température d'une échelle de température à une autre à l'aide des formules suivantes :
- Degrés Celsius à Fahrenheit : ° F = 9/5 (° C) + 32
- Kelvin à Celsius : ° = K - 273,15
- Degrés Fahrenheit à kelvin : K = 5/9 (°F - 32) + 273,15
Notez que la méthode String.format("%.2f", /* measurement */ )
permet de convertir un nombre en type String
avec deux décimales.
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.")
}
Exécutez la fonction main()
pour qu'elle appelle la fonction printFinalTemperature()
et affiche les lignes suivantes. Vous devrez transmettre des arguments pour la formule de température et de conversion. Conseil : Nous vous recommandons d'utiliser des valeurs Double
pour éviter la troncation de l'entier (Integer
) lors des opérations de division.
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. Catalogue de chansons
Imaginez que vous deviez créer une application de lecture de musique.
Créez une classe pouvant représenter la structure d'une chanson. La classe Song
devra inclure les éléments de code suivants :
- Propriétés de la chanson, artiste, année de publication et nombre de lectures
- Propriété indiquant si la chanson est populaire (si le nombre de lectures est inférieur à 1 000, considérez-la comme peu populaire)
- Méthode d'impression d'une description de chanson au format suivant :
"[Titre], interprété par [artiste], est sorti en [année de publication]."
6. Profil Internet
Il arrive souvent de devoir remplir des profils contenant des champs obligatoires et non obligatoires sur certains sites Web. Par exemple, vous pouvez ajouter vos informations personnelles et créer un lien vers les tiers qui vous ont conseillé de créer ce profil.
Dans le code initial fourni dans l'extrait de code suivant, rédigez un programme qui imprimera les détails du profil d'une personne.
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
}
}
Exécutez la fonction showProfile()
pour que le programme imprime les lignes suivantes :
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. Téléphones pliables
En général, l'écran d'un téléphone s'allume et s'éteint lorsque l'utilisateur appuie sur le bouton Marche/Arrêt. En revanche, si un téléphone pliable est plié, son écran interne principal ne s'allume pas lorsque vous appuyez sur ce bouton.
Dans le code initial fourni dans l'extrait de code suivant, écrivez une classe FoldablePhone
qui héritera de la classe Phone
. Elle doit contenir les éléments suivants :
- Une propriété qui indique si le téléphone est plié
- Un comportement de la fonction
switchOn()
différent de celui de la classePhone
pour que l'écran ne s'allume que lorsque le téléphone n'est pas plié - Des méthodes permettant de modifier l'état du pliage
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. Enchère spéciale
Lors d'une mise aux enchères, l'enchère la plus élevée détermine généralement le prix d'un article. Dans cette enchère spéciale, si personne n'enchérit pour un objet, celui-ci est automatiquement cédé à l'hôtel des ventes au prix minimum.
Dans le code initial fourni dans l'extrait de code suivant, une fonction auctionPrice()
(qui accepte un type Bid?
pouvant avoir une valeur nulle en tant qu'argument) vous est fournie :
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.
}
Exécutez la fonction auctionPrice()
pour que le programme imprime les lignes suivantes :
Item A is sold at 5000. Item B is sold at 3000.
9. Code de solution
Notifications mobiles
La solution utilise une instruction if/else
pour imprimer le message de notification approprié en fonction du nombre de messages de notification reçus :
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.")
}
}
Prix du billet de cinéma
La solution utilise une expression when
pour renvoyer le prix approprié du billet en fonction de l'âge du spectateur. Elle utilise également une expression if/else
simple pour l'une des branches de l'expression when
afin d'ajouter la condition supplémentaire dans la tarification standard des billets.
Le prix du billet dans la branche else
renvoie une valeur -1
, qui indique que l'ensemble de prix n'est pas valide pour la branche else
. Une implémentation plus efficace consiste à renvoyer une exception pour la branche else
. Vous vous familiariserez davantage avec le traitement des exceptions dans les prochains modules.
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
}
}
Convertisseur de température
La solution nécessite de transmettre une fonction en tant que paramètre à la fonction printFinalTemperature()
. La solution la plus succincte transmet les expressions lambda en tant qu'arguments, utilise la référence de paramètre it
à la place des noms de paramètre et exploite la syntaxe lambda de fin.
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.")
}
Catalogue de chansons
La solution contient une classe Song
avec un constructeur par défaut qui accepte tous les paramètres obligatoires. La classe Song
comporte également une propriété isPopular
qui utilise une fonction getter personnalisée et une méthode qui imprime la description d'elle-même. Vous pouvez créer une instance de cette classe dans la fonction main()
et appeler ses méthodes pour vérifier si l'implémentation est correcte. Vous pouvez aussi utiliser des traits de soulignement lors de l'écriture des grands nombres, tels que la valeur 1_000_000
, pour améliorer la lisibilité.
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.")
}
}
Lorsque vous appelez la fonction println()
au niveau des méthodes de l'instance, le programme peut afficher cette sortie :
We Don't Talk About Bruno, performed by Encanto Cast, was released in 2022. true
Profil Internet
La solution contient des vérifications de valeur nulle dans différentes instructions if/else
pour imprimer différents textes selon que les propriétés de classe sont null
ou non :
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")
}
}
Téléphones pliables
Pour que la classe Phone
soit une classe parent, vous devez l'ouvrir en ajoutant le mot clé open
avant son nom. Pour remplacer la méthode switchOn()
dans la classe FoldablePhone
, vous devez rendre la méthode située dans la classe Phone
accessible en ajoutant le mot clé open
avant la méthode.
La solution contient une classe FoldablePhone
avec un constructeur par défaut qui inclut un argument par défaut pour le paramètre isFolded
. La classe FoldablePhone
permet également de remplacer la propriété isFolded
par une valeur true
ou false
. Elle remplace également la méthode switchOn()
héritée de la classe Phone
.
Vous pouvez créer une instance de cette classe dans la fonction main()
et appeler ses méthodes pour vérifier si l'implémentation est correcte.
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()
}
La sortie est la suivante :
The phone screen's light is off. The phone screen's light is on.
Enchère spéciale
La solution utilise l'opérateur d'appel sécurisé ?.
et l'opérateur Elvis ?:
pour renvoyer le prix correct :
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. Exercices supplémentaires
Pour vous entraîner davantage en langage Kotlin, consultez le cours sur les bases du langage Kotlin, proposé par JetBrains Academy. Consultez la fiche info afin d'accéder à la liste des sujets abordés dans ce cours et de choisir celui qui vous intéresse.