{"id":34296,"date":"2020-05-19T08:45:16","date_gmt":"2020-05-19T07:45:16","guid":{"rendered":"https:\/\/blog.jetbrains.com\/fr\/?p=735"},"modified":"2020-05-19T08:45:16","modified_gmt":"2020-05-19T07:45:16","slug":"premier-apercu-de-kotlin-1-4-m2-ameliorations-de-la-bibliotheque-standard","status":"publish","type":"post","link":"https:\/\/blog.jetbrains.com\/fr\/2020\/05\/19\/premier-apercu-de-kotlin-1-4-m2-ameliorations-de-la-bibliotheque-standard\/","title":{"rendered":"Premier aper\u00e7u de Kotlin 1.4-M2\u00a0: am\u00e9liorations de la biblioth\u00e8que standard"},"content":{"rendered":"Nous continuons de travailler sur Kotlin 1.1.4 et la prochaine preview 1.4-M2 est pour bient\u00f4t. En attendant la preview, nous sommes pr\u00eats \u00e0 vous d\u00e9voiler quelques unes de ses principales am\u00e9liorations.\r\n\r\nDans cet article, nous vous pr\u00e9sentons les \u00e9volutions de la biblioth\u00e8que standard :\r\n\r\n\tModifications de l'API existante comme la mise \u00e0 jour des signatures et l'introduction de nouvelles constantes\r\n\tAjout de fonctions dans la biblioth\u00e8que commune\r\n\tNouvelles fonctions pour les tableaux et les collections\r\n\tAm\u00e9liorations de la d\u00e9l\u00e9gation de propri\u00e9t\u00e9\r\n\r\nBien que Kotlin 1.4-M2 ne soit pas encore sorti, nous avons d\u00e9ploy\u00e9 sa premi\u00e8re version sur Kotlin playground afin que vous puissiez essayer tout ce que vous trouverez dans cet article. Les exemples de code pr\u00e9sent\u00e9s dans cet article fonctionnent \u00e9galement avec la nouvelle version.\r\n\r\nSi vous avez h\u00e2te d'essayer la version 1.4-M2 \u00e0 venir, inscrivez-vous \u00e0 la newsletter du blog Kotlin pour \u00eatre notifi\u00e9 de sa disponibilit\u00e9.\r\n\r\n&nbsp;\r\nExtension de la biblioth\u00e8que commune\r\nVous pouvez utiliser la biblioth\u00e8que standard dans le code \"commun\", c'est-\u00e0-dire le code partag\u00e9 entre diff\u00e9rentes plateformes, qu'il s'agisse d'Android et iOS ou de JVM et JS. Nous \u00e9tendons progressivement la biblioth\u00e8que commune et y ajoutons des fonctionnalit\u00e9s.\r\n\r\nLa pr\u00e9c\u00e9dente impl\u00e9mentation de appendln dans Kotlin\/JVM a apport\u00e9 un s\u00e9parateur de ligne d\u00e9pendant du syst\u00e8me (\\n sur les syst\u00e8mes UNIX et \\r\\n sur Windows). Cependant, nous pensons qu'il est important de garantir le m\u00eame comportement ind\u00e9pendamment du syst\u00e8me d'exploitation et de la plateforme sous-jacente si nous parlons de code commun. C'est pourquoi nous avons abandonn\u00e9 la fonction appendln au profit de la nouvelle fonction appendLine, qui termine toujours les lignes avec un caract\u00e8re unique \\n\u00a0:\r\nfun main() {\r\n\/\/sampleStart\r\n   println(buildString {\r\n       appendLine(\"Hello,\")\r\n       appendLine(\"Kotlin 1.4-M2\")\r\n   })\r\n\/\/sampleEnd\r\n}\r\n\r\nVous pouvez toujours utiliser System.lineSeparator() dans la JVM lorsque vous avez besoin d'un s\u00e9parateur sp\u00e9cifique \u00e0 la plateforme.\r\n\r\nLes autres fonctions qui peuvent maintenant \u00eatre utilis\u00e9es dans le code commun vous permettent d'utiliser la repr\u00e9sentation de cha\u00eene de la trace de pile indiqu\u00e9e. L'extension Throwable.stackTraceToString() renvoie la description d\u00e9taill\u00e9e de ce throwable avec sa trace de pile, et Throwable.printStackTrace() imprime cette description sur la sortie d'erreur standard.\r\n\r\nDans le code commun, vous pouvez \u00e9galement utiliser la fonction Throwable.addSuppressed(), qui vous permet de sp\u00e9cifier les exceptions qui ont \u00e9t\u00e9 supprim\u00e9es afin de d\u00e9livrer l'exception, et la propri\u00e9t\u00e9 Throwable.suppressedExceptions, qui renvoie une liste de toutes les exceptions supprim\u00e9es.\r\nNouvelles fonctions de tableau\r\nNous avons ajout\u00e9 de nouvelles fonctions d'extension pour les tableaux afin de vous proposer une exp\u00e9rience plus harmonieuse lorsque vous travaillez avec diff\u00e9rents types de conteneurs \u00a0:\r\n\r\n\tshuffle() - place les \u00e9l\u00e9ments du tableau dans un ordre al\u00e9atoire.\r\n\tonEach() - effectue l'action indiqu\u00e9e sur chaque \u00e9l\u00e9ment du tableau et retourne le tableau lui-m\u00eame.\r\n\r\nCes fonctions devraient \u00eatre famili\u00e8res \u00e0 ceux qui utilisent les listes ; elles fonctionnent de la m\u00eame mani\u00e8re pour les tableaux.\r\nfun main() {\r\n\/\/sampleStart\r\n    var language = \"\"\r\n    val letters = arrayOf(\"k\", \"o\", \"t\", \"l\", \"i\", \"n\")\r\n    val fileExt = letters.onEach { language += it }\r\n       .filterNot { it in \"aeuio\" }.take(2)\r\n       .joinToString(prefix = \".\", separator = \"\")\r\n    println(language) \/\/ \"kotlin\"\r\n    println(fileExt) \/\/ \".kt\"\r\n\r\n    letters.shuffle()\r\n    println(letters.contentToString())\r\n\/\/sampleEnd\r\n}\r\n\r\nNous avons \u00e9galement ajout\u00e9 de nouvelles fonctions pour le tri des sous-plages de tableaux. Auparavant, la fonction sort() avec les param\u00e8tres fromIndex et toIndex, \u00e9tait limit\u00e9e \u00e0 la JVM. Cette fonction est d\u00e9sormais commune, et non plus limit\u00e9e \u00e0 la JVM, de m\u00eame que deux nouvelles fonctions connexes, qui sont des versions sous-plages de reverse() et sortDescending(). Chacune d'entre elles prend deux index et r\u00e9ordonne les \u00e9l\u00e9ments entre eux (en incluant fromIndex mais en excluant toIndex), de la mani\u00e8re indiqu\u00e9e par leur nom\u00a0:\r\n\r\n\treverse() pour les sous-plages de tableau inverse l'ordre des \u00e9l\u00e9ments dans la sous-plage.\r\n\tsortDescending() pour les sous-plages de tableau trie les \u00e9l\u00e9ments de la sous-plage par ordre d\u00e9croissant.\r\n\r\nfun main() {\r\n\/\/sampleStart\r\n    val letters = arrayOf(\"i\", \"o\", \"k\", \"l\", \"t\", \"n\")\r\n    letters.reverse(0, 3)\r\n    letters.sortDescending(2, 5)\r\n    println(letters.contentToString()) \/\/ [k, o, t, l, i, n]\r\n\/\/sampleEnd\r\n}\r\n\r\nNouvelles fonctions de l'API des collections\r\nDans la version 1.4-M2, nous continuons \u00e0 d\u00e9velopper l'API des collections dans la biblioth\u00e8que standard pour couvrir davantage de cas d'utilisation r\u00e9els\u00a0:\r\n\r\n\tUne nouvelle fonction setOfNotNull() cr\u00e9e un ensemble compos\u00e9 de tous les \u00e9l\u00e9ments non null parmi les arguments fournis.\r\n\r\nfun main() {\r\n\/\/sampleStart\r\n    val set = setOfNotNull(null, 1, 2, 0, null)\r\n    println(set)\r\n\/\/sampleEnd\r\n}\r\n\r\n\r\n\tshuffled() est maintenant disponible pour les s\u00e9quences.\r\n\r\nfun main() {\r\n\/\/sampleStart\r\n    val numbers = (0 until 50).asSequence()\r\n    val result = numbers.map { it * 2 }.shuffled().take(5)\r\n    println(result.toList()) \/\/five random even numbers below 100\r\n\/\/sampleEnd\r\n}\r\n\r\n\r\n\tonEachIndexed() et reduceIndexedOrNull() ont \u00e9t\u00e9 respectivement ajout\u00e9s comme \u00e9quivalents de onEach() et reduceOrNull(). Comme vous le savez peut-\u00eatre d\u00e9j\u00e0, Indexed dans le nom d'une fonction de traitement de collection signifie que l'op\u00e9ration appliqu\u00e9e a l'index d'\u00e9l\u00e9ment comme param\u00e8tre.\r\n\r\nfun main() {\r\n\/\/sampleStart\r\n    val list = mutableListOf(\"a\", \"b\", \"c\", \"d\").onEachIndexed {\r\n        index, item -&gt; println(index.toString() + \":\" + item)\r\n    }\r\n\r\n    val emptyList = emptyList&lt;Int&gt;()\r\n    emptyList.reduceIndexedOrNull {index, a, b -&gt; index + a + b} \/\/ null\r\n\/\/sampleEnd\r\n}\r\n\r\n\r\n\trunningFold() et runningReduce() ont \u00e9t\u00e9 ajout\u00e9s comme synonymes de scan() et scanReduce(). Ces noms sont plus coh\u00e9rents avec les fonctions connexes fold() et reduce(). \u00c0 l'avenir, scan() sera disponible avec runningFold() car c'est un nom couramment utilis\u00e9 pour cette op\u00e9ration. Cependant, la fonction exp\u00e9rimentale scanReduce() sera bient\u00f4t abandonn\u00e9e et supprim\u00e9e.\r\n\r\n\t\r\nfun main() {\r\n\/\/sampleStart\r\n    val numbers = mutableListOf(0, 1, 2, 3, 4, 5)\r\n    val runningReduceSum = numbers.runningReduce() { sum, item -&gt; sum + item} \/\/ [0, 1, 3, 6, 10, 15]\r\n    val runningFoldSum = numbers.runningFold(10) { sum, item -&gt; sum + item} \/\/ [10, 10, 11, 13, 16, 20, 25]\r\n\/\/sampleEnd\r\n}\r\n\r\nAm\u00e9lioration de l'API existante\r\nKotlin 1.4 \u00e9tant une version majeure, nous pouvons apporter de nouvelles fonctionnalit\u00e9s au langage et de nouvelles fonctions ou interfaces \u00e0 la biblioth\u00e8que standard. Nous n'ajoutons de nouvelles d\u00e9clarations exp\u00e9rimentales que dans les versions incr\u00e9mentielles (comme la version 1.3.70). Si vous \u00e9crivez du code avec Kotlin 1.3.70 et que vous n'utilisez pas de d\u00e9clarations exp\u00e9rimentales, votre code sera tr\u00e8s bien compil\u00e9 pour vos collaborateurs utilisant Kotlin 1.3.40.\r\n\r\nLes versions majeures n'ont pas besoin d'ob\u00e9ir aux m\u00eames r\u00e8gles strictes que les versions mineures, ce qui signifie que si vous utilisez une nouvelle fonctionnalit\u00e9 ou API, le compilateur Kotlin de la version 1.3 ne peut pas compiler le code \u00e9crit en Kotlin 1.4. Cela nous permet d'apporter des modifications \u00e0 l'API afin de l'am\u00e9liorer. Nous veillons \u00e0 la r\u00e9trocompatibilit\u00e9 afin que le code \u00e9crit pour l'ancienne version continue de se compiler et de fonctionner comme auparavant.\r\n\r\nDans Kotlin 1.4, nous avons assoupli plusieurs fonctions pour accepter des valeurs null\u00a0:\r\nfun main() {\r\n\/\/sampleStart\r\n   val s: String? = null\r\n   println(s.toBoolean())  \/\/ false\r\n\/\/sampleEnd\r\n}\r\n\r\nKotlin 1.3 ne compilera pas ce code car il exige que le r\u00e9cepteur de String.toBoolean() soit non-nullable. Kotlin 1.4 change le recepteur en une cha\u00eene nullable : String?.toBoolean(). N\u00e9anmoins, tout le code que vous avez \u00e9crit auparavant continue de compiler et de fonctionner avec Kotlin 1.4.\r\n\r\nLa m\u00eame logique s'applique au r\u00e9cepteur Array des fonctions contentEquals, contentHashCode et contentToString\u00a0: il est maintenant nullable. De m\u00eame, String.format() permet d\u00e9sormais d'utiliser null comme argument locale, auquel cas aucune localisation n'est appliqu\u00e9e.\r\n\r\nLes constantes suivantes d\u00e9finies dans Double et Float sont d\u00e9sormais des constantes \"r\u00e9elles\"\u00a0:\r\nfun main() {\r\n\/\/sampleStart\r\n    println(Double.NaN)  \/\/ NaN\r\n    println(Double.NEGATIVE_INFINITY)  \/\/ -Infinity\r\n    println(Double.POSITIVE_INFINITY &gt; Double.MAX_VALUE )  \/\/ true\r\n    println(Double.SIZE_BITS) \/\/ 64\r\n\/\/sampleEnd\r\n}\r\n\r\nElles sont maintenant d\u00e9finies comme des variables const , vous pouvez donc les utiliser comme arguments d\u2019annotation.\r\n\r\nSIZE_BITS et SIZE_BYTES sont de nouvelles constantes dans Double et Float ; elles contiennent le nombre de bits et d'octets utilis\u00e9s pour repr\u00e9senter une instance du type sous forme binaire.\r\n\r\nNotez que nous avons \u00e9galement modifi\u00e9 les valeurs Float.MAX_VALUE et Float.MIN_VALUE dans Kotlin\/JS. Auparavant, elles \u00e9taient \u00e9gales au Number.MAX\/MIN_VALUE de JavaScript, ou de mani\u00e8re \u00e9quivalente, \u00e0 Double.MAX\/MIN_VALUE, car Float est sensiblement \u00e9quivalent \u00e0 Double dans Kotlin\/JS. D\u00e9sormais, ces constantes Float sont les m\u00eames pour toutes les plateformes.\r\nmaxOf() et minOf() avec vararg\r\nLes fonctions maxOf() et minOf() de la biblioth\u00e8que standard trouvent la plus grande et la plus petite de deux valeurs. \u00c0 partir de la version 1.4-M1, maxOf() et minOf() peuvent accepter un nombre variable d'arguments (vararg), ce qui vous permet de les utiliser sur n'importe quel ensemble de nombres ou autres \u00e9l\u00e9ments comparables.\r\nfun main() {\r\n\/\/sampleStart\r\n    val max = maxOf(1, 2, 3, 4)\r\n    println(max)\r\n\/\/sampleEnd\r\n}\r\n\r\nAm\u00e9liorations de la d\u00e9l\u00e9gation de propri\u00e9t\u00e9\r\nDans Kotlin, les propri\u00e9t\u00e9s d\u00e9l\u00e9gu\u00e9es fonctionnent via des conventions, et non des interfaces\u00a0: le type que vous voulez utiliser en tant que d\u00e9l\u00e9gu\u00e9 doit d\u00e9finir une fonction d'op\u00e9rateur plut\u00f4t que d'impl\u00e9menter l'interface requise. Cela donne une certaine flexibilit\u00e9 (car nous ne sommes pas li\u00e9s par des interfaces sp\u00e9cifiques), mais en pratique, il est utile d'utiliser des interfaces dans de nombreux cas.\r\n\r\nDans Kotlin 1.4, nous avons am\u00e9lior\u00e9 le fonctionnement de ces interfaces compl\u00e9mentaires en introduisant une nouvelle interface PropertyDelegateProvider et ReadWriteProperty h\u00e9rite d\u00e9sormais de ReadOnlyProperty. Poursuivez votre lecture pour en savoir plus.\r\nExpression Delegate\r\nLes interfaces ReadWriteProperty et ReadOnlyProperty sont pratiques pour d\u00e9finir les d\u00e9l\u00e9gu\u00e9s de propri\u00e9t\u00e9 car votre classe personnalis\u00e9e ou votre objet anonyme peut les impl\u00e9menter\u00a0:\r\nfun myDelegate(): ReadWriteProperty&lt;Nothing?, Int&gt; =\r\n   object : ReadWriteProperty&lt;Nothing?, Int&gt; {\r\n      ...\r\n   }\r\n\r\nval foo: Int by myDelegate()\r\nvar bar: Int by myDelegate()\r\n\r\n\u00c0 partir de la version 1.4, ReadWriteProperty h\u00e9rite de ReadOnlyProperty. Cela vous donne plus de flexibilit\u00e9 pour travailler avec les expressions delegate. Dans notre exemple, vous pouvez maintenant passer l'appel myDelegate() chaque fois qu'un ReadOnlyProperty est attendu.\r\n\r\nNous voulons souligner ici que \"read-only\" n\u2019\u00e9quivaut pas \u00e0 \"non modifiable\" dans Kotlin, tout comme une liste en lecture seule n'est pas une liste non modifiable. \"Read-only\" signifie que \"cette interface fournit uniquement un acc\u00e8s en lecture seule \u00e0 l'objet en question\".\r\nMise \u00e0 disposition d'un delegate\r\nEn utilisant le m\u00e9canisme de mise \u00e0 disposition d'un delegate, vous pouvez \u00e9tendre la logique de cr\u00e9ation d'un objet \"d\u00e9l\u00e9gu\u00e9\", c'est-\u00e0-dire l'objet auquel l'impl\u00e9mentation de la propri\u00e9t\u00e9 est d\u00e9l\u00e9gu\u00e9e. Vous pouvez trouver les d\u00e9tails de son fonctionnement dans la documentation. Dans la version 1.4, pour rendre ce m\u00e9canisme un peu plus pratique, nous avons ajout\u00e9 une nouvelle interface PropertyDelegateProvider. Vous pouvez l'utiliser lorsque vous ne souhaitez pas cr\u00e9er une classe suppl\u00e9mentaire et que vous pr\u00e9f\u00e9rez utiliser un objet anonyme, comme dans l'exemple ci-dessus de myDelegate().\r\nD\u00e9l\u00e9gation \u00e0 une autre propri\u00e9t\u00e9\r\n\u00c0 partir de la version 1.4, une propri\u00e9t\u00e9 peut d\u00e9l\u00e9guer ses getter et setter directement \u00e0 une autre propri\u00e9t\u00e9. Cela peut par exemple \u00eatre utile lorsque vous souhaitez renommer une propri\u00e9t\u00e9 de mani\u00e8re r\u00e9trocompatible\u00a0: vous introduisez une nouvelle propri\u00e9t\u00e9, vous annotez une ancienne avec l'annotation @Deprecated et vous d\u00e9l\u00e9guez son impl\u00e9mentation.\r\nclass MyClass {\r\n   var newName: Int = 0\r\n   @Deprecated(\"Use 'newName' instead\", ReplaceWith(\"newName\"))\r\n   var oldName: Int by this::newName\r\n}\r\n\r\nfun main() {\r\n   val myClass = MyClass()\r\n   \/\/ Notification: 'oldName: Int' is deprecated.\r\n   \/\/ Use 'newName' instead\r\n   myClass.oldName = 42\r\n   println(myClass.newName) \/\/ 42\r\n}\r\n\r\nL'optimisation pour les propri\u00e9t\u00e9s d\u00e9l\u00e9gu\u00e9es compil\u00e9es d\u00e9crite pr\u00e9c\u00e9demment fonctionne dans ce cas. Comme l'impl\u00e9mentation de l'op\u00e9rateur de d\u00e9l\u00e9gation n'utilise pas les informations sur la propri\u00e9t\u00e9 d\u00e9l\u00e9gu\u00e9e (oldName), il n'est pas n\u00e9cessaire que le compilateur g\u00e9n\u00e8re l'instance KProperty avec ces informations. \u00c0 l'avenir, il sera \u00e9galement possible de ne pas g\u00e9n\u00e9rer d'instance KMutableProperty suppl\u00e9mentaire pour le d\u00e9l\u00e9gu\u00e9 (newName).\r\nComment essayer\r\nToutes ses modifications seront incluses dans la preview de Kotlin 1.4-M2, mais vous pouvez d\u00e9j\u00e0 les essayer en ligne surplay.kotl.in, en s\u00e9lectionnant la version version 1.4-M2 dans les param\u00e8tres.\r\nNotes de pr\u00e9-version\r\nVeuillez noter que les garanties de r\u00e9trocompatibilit\u00e9 ne s'appliquent pas aux versions pr\u00e9liminaires. Les fonctionnalit\u00e9s et l'API peuvent \u00eatre amen\u00e9es \u00e0 changer dans les versions ult\u00e9rieures en fonction de vos retours.\r\nFaites-nous part de vos commentaires\r\nNous vous remercions pour tous les rapports de bugs que vous partagez dans notre outil de suivi. Nous ferons de notre mieux pour traiter et solutionner tous les probl\u00e8mes importants d'ici la sortie de la version finale.\r\n\r\nNous vous invitons \u00e0 rejoindre le canal \\#eap sur le Slack Kotlin (demandez une invitation ici) pour y poser vos questions, participer aux discussions et recevoir en avant-premi\u00e8re les notifications sur les nouvelles versions.\r\n\r\nFaison \u00e9voluer Kotlin ensemble !\r\n\r\nAuteur de l'article original en anglais :\u00a0Pavel Semyonov","protected":false},"excerpt":{"rendered":"Nous continuons de travailler sur Kotlin 1.1.4 et la prochaine preview 1.4-M2 est pour bient\u00f4t. En attendant la preview, nous sommes pr\u00eats \u00e0 vous d\u00e9voiler quelques unes de ses principales am\u00e9lioration","protected":false},"author":{"name":"Delphine Massenhove","link":"https:\/\/blog.jetbrains.com\/fr\/author\/delphine-massenhovejetbrains-com"},"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[],"tags":[600],"cross-post-tag":[],"acf":[],"featured_image":null,"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/posts\/34296"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/813"},{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/813"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=34296"}],"version-history":[{"count":0,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/posts\/34296\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=34296"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=34296"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=34296"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=34296"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}