Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
May 27, 2021 01:10 pm GMT

De Kotlin Java en 20 minutes

Cet article est ddi aux dveloppeurs Java qui ont entendu parler de Kotlin, mais ne s'y sont encore jamais frotts.

quoi ressemblerait leur dcouverte de Kotlin?

Une sance de mob-programming avec des collgues m'a permis d'en avoir une petite ide....

Show Me the Code!

Vous pouvez lire l'article, mais vous en tirerez davantage encore en suivant dans votre IDE l'volution du code.

Pour cela, vous avez besoin de IntelliJ Community Edition. Qui est gratuit!

Sur MacOS par exemple, vous pouvez l'installer avec $ brew install intellij-idea-ce

Le repository se trouve ci-dessous, et les commits dcrits sont prsent dans cette pull-request.

Kata: the observed PIN

https://www.codewars.com/kata/5263c6999e0f40dee200059d/train/java

Alright, detective, one of our colleagues successfully observed our target person, Robby the robber. We followed him to a secret warehouse, where we assume to find all the stolen stuff. The door to this warehouse is secured by an electronic combination lock. Unfortunately our spy isn't sure about the PIN he saw, when Robby entered it.

The keypad has the following layout:

 1  2  3  4  5  6  7  8  9      0     

He noted the PIN 1357, but he also said, it is possible that each of the digits he saw could actually be another adjacent digit (horizontally or vertically, but not diagonally). E.g. instead of the 1 it could also be the 2 or 4. And instead of the 5 it could also be the

Mais tout d'abord un peu de contexte.

Mob-programming

Mes collgues Sarah et Pierre sommes en train de faire avec moi une session Mob programming

Le but est de rsoudre le kata du PIN observ approximativement, dans lequel un espion moyennement fiable nous indique avoir vu le PIN 1357. Mais il n'est pas trs sr de lui, chaque chiffre pourrait tre la place un de ses voisins sur le pav numrique. Le code pourrait donc tre 1357 mais aussi par exemple 2357 ou 1368.

Le projet est un projet Java/Maven. Il contient deux fichiers : PinGuesser.java et PinGuesserTest.java. Le projet a un temps de compilation et d'excution des tests qui se comptent en secondes, pas en minutes comme dans beaucoup d'applications Android. Plus sympa en tant que dveloppeur mon avis.

Nous utilisons le plugin Code With Me d'IntelliJ pour pouvoir faire du mob-programming.

Nous nous dbrouillons bien: nous avons russi rsoudre le Kata puis le refactorer un tat satisfaisant.

Mais il nous reste 20 minutes!

  • Sarah : Vous voyez quelque-chose amliorer?
  • Pierre : Pas trop, a m'a lair bien comme a.
  • Moi : Il nous reste 20 minutes, pourquoi pas tout rcrire en Kotlin?
  • Sarah : Oh, j'ai entendu parler de Kotlin, mais n'ai jamais eu l'occasion de l'essayer. Tout de mme, 20 minutes, est-ce que c'est faisable?
  • Moi : Lanons nous, on verra bien ce que a donne!

Configure Kotlin in project

  • Pierre : Ok, moi je n'ai jamais fait de Kotlin de ma vie. Dis-moi quoi faire.
  • Moi : IntelliJ a une ActionConvert Java File to Kotlin File. C'est une bonne manire de dmarrer!
  • Pierre : Ok, j'essaye!

https://user-images.githubusercontent.com/459464/118158571-42ef6000-b41c-11eb-89df-c32de3ffe8f0.png

https://user-images.githubusercontent.com/459464/118158602-4d115e80-b41c-11eb-8cb6-ee85143251ae.png

  • Pierre : IntelliJ me dit que Kotlin n'est pas configur dans le projet. Il n'a pas tort!
  • Pierre : Comment je configure Kotlin dans un projet Maven?
  • Moi : Je ne sais pas, j'ai toujours utilis Gradle.
  • Moi : Laisse IntelliJ le faire!
  • Moi : Au passage, c'est quivalent excuter l'action Tools > Kotlin > Configure Kotlin in project
  • Pierre : Allons y.
  • Pierre : a a l'air d'avoir march, le fichier pom.xml a t modifi.
  • Pierre : first commit

Dire Java que @ParametersAreNonnullByDefault

  • Moi : Avant d'essayer le convertisseur Java -> Kotlin, il y a une tape pralable. Comme vous en avez peut-tre entendu parler, Kotlin intgre la gestion de la nullabilit dans son systme de type. Mais pas Java, qui par dfaut autorise null partout. Du coup le convertisseur autoriserait null partout lui aussi. Ce qui est techniquement correct, mais pas ce que nous voulons.
  • Sarah : Mais il y a des annotations en Java pour dire si la valeur nulll est autorise ou non, pas vrai?
  • Moi : Exactement, et l'annotation qui nous intresse est @ParametersAreNonnullByDefault de la JSR 305. Elle s'applique tout un package et informe que par dfaut les paramtres sont non-nulls. a tombe bien, c'est exactement comme cela que a marche en Kotlin!
  • Moi : commit
diff --git a/pom.xml b/pom.xml     <dependencies>+        <dependency>+            <groupId>com.google.code.findbugs</groupId>+            <artifactId>jsr305</artifactId>+            <version>3.0.2</version>+        </dependency>+++ b/src/main/java/pin/package-info.java@@ -0,0 +1,4 @@+@ParametersAreNonnullByDefault+package pin;++import javax.annotation.ParametersAreNonnullByDefault;

PinGuesser: Convert Java File to Kotlin File

  • Pierre : J'imagine que maintenant je peux ouvrir PinGuesser.java et relancer l'action Convert Java File to Kotlin File ?
  • Moi : Correct
  • Pierre : Apparemment.... a a march? En tout cas il y a un fichier PinGuesser.kt
  • Moi : Comment peux-tu t'assurer que a a vraiment march?
  • Sarah : Tu devrais lancer les tests unitaires
  • Pierre : Ah oui...

https://user-images.githubusercontent.com/459464/117936889-aaff5280-b305-11eb-9c84-be7205e9673c.png

  • Pierre : Tout est au vert! C'est dingue, j'ai cris mon premier code en Kotlin, et il est bug-free du premier coup.
  • Sarah : Bravo!
  • Pierre : Il reste les tests. On doit les convertir aussi, non?
  • Moi : Pas forcment, a marche aussi comme a. Java et Kotlin peuvent co-exister pacifiquement dans le mme repository grace leur interoprabilit.
  • Sarah : Ok, mais a a l'air fun et je veux moi aussi essayer!
  • Pierre : Je te donne le clavier, juste aprs ce commit

PinGuesserTest: Convert Java File to Kotlin File - et corrections manuelles

  • Sarah : Donc j'ouvre PinGuesserTest.java et j'excute l'action... Comment s'appelle t'elle?
  • Pierre : Convert Java File to Kotlin File
  • Sarah : C'est parti!
  • Sarah : J'ai maintenant un fichier PinGuesserTest.kt . Il contient des erreurs ceci dit...

https://user-images.githubusercontent.com/459464/117937632-80fa6000-b306-11eb-931b-7642e4aac07a.png

  • Pierre : ta place j'appliquerais la suggestion d'optimiser les imports.
  • Sarah : Ok.
  • Sarah : a a march.
  • Moi : Comme vous voyez le convertisseur n'est pas parfait. Mais je trouve que c'est un formidable outil d'apprentissage car il vous permet de prendre quelque-chose que vous connaissez dj - Java - et de le convertir en ce que vous voulez apprendre.
  • Sarah : Je lance les tests unitaires par acquis de conscience.
  • Sarah : Ouh j'ai des erreurs bizarres dans jUnit.

https://user-images.githubusercontent.com/459464/118160523-b3977c00-b41e-11eb-8151-a4dea10aa9e2.png

  • Moi : Je crois que je comprends le message d'erreur : l o Java a des mthodes static, Kotlin utilise des mthodes dfinies dans le companion object { ... } de la classe. En gnral c'est presque la mme chose, mais l jUnit veut vraiment avoir faire des mthodes statiques, ce qui peut se corriger avec une annotation :
-        fun testSingleDigitParameters(): Stream<ArguMents> {+        @JvmStatic fun testSingleDigitParameters(): Stream<Arguments> {             return Stream.of(                 Arguments.of("1", java.util.Set.of("1", "2", "4")),                 Arguments.of("2", java.util.Set.of("1", "2", "3", "5")),@@ -61,7 +58,7 @@ internal class PinGuesserTest {             )         }-        fun invalidParams(): Stream<Arguments> {+        @JvmStatic  fun invalidParams(): Stream<Arguments> {             return Stream.of(                 Arguments.of("   "),                 Arguments.of("A"),
  • Sarah : Les tests sont au vert!
  • Sarah : Comme promis, le projet est maintenant 100% en Kotlin
  • Sarah : commit

Utiliser la librairie Kotlin standard

  • Pierre : C'est quoi la prochaine tape?
  • Moi : Il est possible de crer List, Set et Map comme on le fait traditionnellement en Java. Mais la librairie Kotlin standard contient plein de fonctions utilitaires qui rsolvent lgamment des petits problmes courants. Je vous montre a :

https://user-images.githubusercontent.com/459464/118299183-b6f33c00-b4e0-11eb-9458-c8322d65cae9.png

  • Moi :Je prfre comme a. Est-ce que les tests sont toujours au vert?
  • Moi : Oui ils le sont, donc commit.

Remplacer l'API Streams par la librairie Kotlin standard

  • Moi : Une autre chose que contient la librairie Kotlin standard sont les fonctions .map(), .filter(), .flatmap() - et bien d'autres encore - qu'on retrouve dans les langages fonctionnels.
  • Sarah : Un peut comme l'API stream() que nous avons utilis en Java ?
  • Moi : C'est a, mais plus performant dans son implmentation et moins verbeux :
-    fun combineSolutions(pins1: Set<String>, pins2: Set<String>): Set<String> {-        return pins1.stream()-            .flatMap { pin1: String ->-                pins2-                    .stream()-                    .map { pin2: String -> pin1 + pin2 }-            .collect(Collectors.toSet())-    }+    fun combineSolutions(pins1: Set<String>, pins2: Set<String>): Set<String> =+        pins1.flatMap { pin1 ->+            pins2.map { pin2 ->+                "$pin1$pin2"+             }+        }.toSet()
  • Sarah : Les tests passent toujours.
  • Sarah : commit

Utiliser par dfaut des proprits read-only (val)

  • Moi : Dans le code Kotlin idiomatique, on essaye d'utiliser le plus possible les val property au lieu de var property.
  • Pierre : Quelle est la diffrence?
  • Moi : val property est read-only, il n'a pas de setter, c'est comme un final field en Java
  • Pierre : Je vois. Donc je remplace juste les var pas des val?
  • Moi : Oui c'est a.
  • Pierre : Facile.
  • Pierre : commit.

Fail fast

  • Sarah : Est-ce qu'il y a un moyen idiomatique en Kotlin de vrifier les paramtres?
  • Sarah : On s'attend ce que le PIN soit quelque-chose comme 7294, c'est dire qu'il ne contiennent que des chiffres.
  • Moi : Oui, tu peux utiliser require(condition) { "Message d'erreur" } .
  • Sarah : Cela donnerait quoi ici?
fun getPINs(observedPin: String): Set<String> {    require(observedPin.all { it in '0'..'9' }) { "PIN $observedPin is invalid" }    // rest goes here}

Passer un style plus fonctionnel

  • Sarah : Quelle est la prochaine tape?
  • Moi : Je voudrais librer les fonctions.
  • Pierre : C'est dire?
  • Moi : Regardez, nous avons cette classe PinGuesser . Mais qu'est-ce qu'elle fait exactement? Elle ne fait rien d'autre qu'tre un bte namespace.
  • Moi : Cette classe un nom qui nous empche d'accder directement aux verbes - les fonctions - qui font tout le travail.
  • Moi : C'est ce que montre un de mes essais favoris sur la programmation : "Execution in the kingdom of nouns" de Steve Yegge.
  • Sarah : Je connais cette diatribe, elle est hilarante !
  • Sarah : Alors comment libre-t'on les verbes / fonctions ?
  • Moi : Nous supprimons la classe et transformons ses mthodes en fonctions top-level :
diff --git a/src/main/java/pin/PinGuesser.kt b/src/main/java/pin/PinGuesser.ktindex 17a20b3..38e457c 100644--- a/src/main/java/pin/PinGuesser.kt+++ b/src/main/java/pin/PinGuesser.kt@@ -1,9 +1,5 @@ package pin-import java.util.stream.Collectors--class PinGuesser {-    companion object {         val mapPins = mapOf(             "1" to setOf("1", "2", "4"),             "2" to setOf("1", "2", "3", "5"),@@ -16,7 +12,6 @@ class PinGuesser {             "9" to setOf("6", "8", "9"),             "0" to setOf("0", "8"),         )-    }     fun getPINs(observedPin: String): Set<String> {         for (c in observedPin.toCharArray()) {@@ -38,5 +33,4 @@ class PinGuesser {             pins2.map { pin2 ->                 "$pin1$pin2"             }-        }.toSet()-}--- a/src/test/java/PinGuesserTest.kt+++ b/src/test/java/PinGuesserTest.ktclass PinGuesserTest {-    val pinGuesser = PinGuesser()     @ParaMoiterizedTest     @MoithodSource("testSingleDigitParaMoiters")     fun testSingleDigit(observedPin: String?, expected: Set<String?>?) {-        val actual = pinGuesser.getPINs(observedPin!!)+        val actual = getPINs(observedPin!!)         Assertions.assertEquals(expected, actual)     }

List.fold()

  • Pierre : Est-ce qu'on peut prendre un peu de recul l ? quoi cela sert-il de rendre le code plus "beau", plus idiomatique? Au final, nos clients s'en foutent.
  • Moi : Et bien je ne sais pas vous, mais moi cela m'arrive frquemment de ne pas vraiment comprendre le code sur lequel je suis cens travailler. Dans ce cas l, je m'investis pour simplifier le code, et un moment donn le code tient dans ma tte et la solution devient vidente.
  • Pierre : Et qu'est-ce qui est devenu vident l par exemple ?
  • Moi : Et bien maintenant que nous avons un code Kotlin idiomatique clean, je me rends compte que la solution du Kata peut s'exprimer par une simple construction fonctionnelle : List.fold().
  • Sarah : Show me the code
  • Moi : commit
fun getPINs(observedPin: String): Set<String> {    require(observedPin.all { it in mapPins }) { "PIN $observedPin is invalid" }    return  observedPin.fold(initial = setOf("")) { acc: Set<String>, c: Char ->        val pinsForChar: Set<String> = mapPins[c]!!        combineSolutions(acc, pinsForChar)    }}fun combineSolutions(pins1: Set<String>, pins2: Set<String>): Set<String> =    pins1.flatMap { pin1 ->        pins2.map { pin2 ->            "$pin1$pin2"        }    }.toSet()

La suite?

J'espre que vous avez aim cet article.

Si vous voulez me contacter, vous trouverez mon mail l'adresse https://jmfayard.dev/

Le code est disponible l'adresse https://github.com/jmfayard/from-java-to-kotlin

Vous devez dmarrer dans la branche java et comparer avec ce que contient la branche kotlin. Voir cette pull-request

Si vous voulez apprendre Kotlin, je vous rfre mon article :


Original Link: https://dev.to/zenika/de-kotlin-a-java-en-20-minutes-56k9

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To