Quel est le meilleur, Kotlin ou futur Java?

introduction

Cet article est l'article du 12ème jour du Calendrier de l'Avent Kotlin 2019.

Je pense que Kotlin a été dit moderne par rapport à Java. Cependant, le cycle de publication de Java est une fois tous les six mois, et il devient un meilleur langage qu'avant, donc je pense que Java est meilleur lorsque l'on considère la maintenabilité future. Il y a aussi une opinion selon laquelle vous vous demandez peut-être laquelle choisir lors de la sélection d'une langue. Par conséquent, je voudrais comparer les dernières tendances Java avec Kotlin et comparer ce qui est plus moderne.

Les cibles de comparaison sont la dernière version de Kotlin et Java 12 ou des fonctionnalités ultérieures. En ce qui concerne Java, la version 13 a été publiée le 18/09/2019, mais cette fois, j'aimerais comparer certaines fonctionnalités susceptibles d'être incluses dans JDK14 en cours de développement et plus tard. Pour les fonctionnalités avant JDK11, je pense qu'il existe de nombreux autres bons articles, veuillez donc les consulter. Ou il peut être ajouté lorsqu'il y a une marge. </ font>

En ce qui concerne les fonctions ajoutées dans chaque version de JDK, l'article de @ nowokay est assez soigné et facile à comprendre, je voudrais donc y faire référence et le comparer avec Kotlin.

Au fait, Kotlin vient juste de commencer à toucher et je pense qu'il y a certaines parties que je ne comprends pas bien, alors s'il vous plaît faites Masakari.

supposition

  • Kotlin 1.3.61
  • Java OpenJDK 14 Early-Access Build 25
    (J'ai utilisé sdkman cette fois)

Comparer avec Java 12

Référence: Résumé de la nouvelle fonctionnalité Java 12

La version Preview de Switch Expressions est également incluse dans 12, mais comme elle est toujours en cours de correction dans JDK14, je l'expliquerai dans JDK14.

CompactNumberFormat CompactNumberFormat a été introduit dans Java 12, mais Kotlin n'a pas de fonctionnalité similaire.

Java


     NumberFormat cnf = NumberFormat.getCompactNumberInstance();
     System.out.println(cnf.format(10000));               //10 000
     System.out.println(cnf.format(10000_0000));          //Cent millions
     System.out.println(cnf.format(10000_0000_0000L));    //1 billion
}

Kotlin


    fun format(number: Long): String {
        return when {
            (number >= 10F.pow(12)) -> {
                floor(number / 10F.pow(12)).toLong().toString() + "Mille milliards"
            }
            (number >= 10F.pow(8)) -> {
                floor(number / 10F.pow(8)).toLong().toString() + "Milliard"
            }
            (number >= 10F.pow(4)) -> {
                floor(number / 10F.pow(4)).toLong().toString() + "Dix mille"
            }
            else -> {
                number.toString()
            }
        }
    }
    println(format(10000))               //10 000
    println(format(10000_0000))          //Cent millions
    println(format(10000_0000_0000L))    //1 billion

Comme il n'y a que 3 unités, j'ai essayé de le faire un peu de force. Java est meilleur ici, n'est-ce pas? Il semble qu'il y ait peu de possibilités de l'utiliser.

String.indent

Si vous utilisez String.indent, il sera affiché avec l'argument spécifié en retrait.

Java


    String s = "Kotlin";
    System.out.println(s);
    System.out.println(s.indent(2));
    // Kotlin
    //  Kotlin

Dans le cas de Kotlin, utilisez String.prependIndent et indentez avec le caractère spécifié. Cette fois, j'ai mis 2 caractères vides, donc 2 caractères seront en retrait.

Kotlin


    val s = "Kotlin"
    println(s)
    println(s.prependIndent("  "))
    // Kotlin
    //  Kotlin

String.transform

Java


    var addresses = Map.of("Mike", "Fukuoka", "John", "Tokyo");
    var population = Map.of("Tokyo", 30000000, "Fukuoka", 2000000);
    var name = "Mike";
    System.out.println(name.transform(addresses::get).transform(population::get));  // 2000000

Kotlin


fun main() {
    val addresses = mapOf("Mike" to "Fukuoka", "John" to "Tokyo")
    val population = mapOf("Tokyo" to 30000000, "Fukuoka" to 2000000)
    val name = "Mike"

    println(name.let(addresses::get)?.let(population::get))  // 2000000
}

Dans Kotlin, vous pouvez l'écrire de la même manière que String.transform en utilisant la fonction let.

@ rmakiyama et @ anatawa12 m'ont appris à écrire String.transform dans Kotlin! Merci beaucoup. </ font>

Collectors.teeing

Cela semble également difficile à réaliser avec une ligne avec Kotlin. J'ai préparé une fonction à la place et je l'ai réalisé.

Java


    Map.Entry<String, Long> map = Stream.of("aaa", "", "bbb", "ccc").
                filter(Predicate.not(String::isEmpty)).
                collect(Collectors.teeing(
                    Collectors.joining(","),
                    Collectors.counting(),
                    Map::entry));
    System.out.println(map);  // aaa,bbb,ccc=3

Kotlin


    fun listToMap(list: List<String>): Map<String, Int> {
        return mutableMapOf(list.joinToString(",") to list.count())
    }
    val list = mutableListOf("aaa", "", "bbb", "ccc")
                    .filter { !it.isBlank() }
                    .toList()
    println(listToMap(list))  // {aaa,bbb,ccc=3}

Files.mismatch

C'est une API pour vérifier si le contenu du fichier est différent.

Java


	Path filePath1 = Path.of("./com/example/jdk12/FilesMismatchFile1.txt");
	Path filePath2 = Path.of("./com/example/jdk12/FilesMismatchFile2.txt");

	long mismatchRow = Files.mismatch(filePath1, filePath2);
	if (mismatchRow == -1) {
	    System.out.println("file is same");
	} else {
	    System.out.println("file is diffarent¥nrow:" + String.valueOf(mismatchRow));
	}
        //Si les fichiers sont les mêmes
        // file is same

        //Si les fichiers sont différents
        // file is diffarent
        // row:24

Kotlin ne semble pas avoir d'API similaire. Puisqu'il est difficile d'écrire le processus, je vais l'omettre ici.

String.isEmpty

Java


    String s = "";
    String n = null;
    if (s.isEmpty()) {
        System.out.println("s is Empty");
    }
    if (n.isEmpty()) {
        System.out.println("n is Empty");
    }

    // s is Empty
    // Exception in thread "main" java.lang.NullPointerException
    //   at com.example.jdk12.StringIsEmpty.main(StringIsEmpty.java:10)

Kotlin


    val s = "";
    val n: String? = null;
    if (s.isEmpty()) {
        println("s is Empty")
    }
    if (n.isNullOrEmpty()) {
        println("n is Null")
    }

    // s is Empty
    // n is Null

Kotlin obtient une erreur de compilation lors de l'utilisation de n.isEmpty (). La sécurité nulle est bonne après tout.

En Java, si vous utilisez ʻisEmpty () pour une variable Null, NPE la sortira. Vous pouvez également compiler en utilisant ʻOptional <String> n = null; et NPE se produira. Je me demande si Java pourra effectuer des vérifications Null et Empty en même temps sans utiliser de bibliothèque.

Comparer avec Java 13

Référence: https://openjdk.java.net/projects/jdk/13/

Les expressions de commutation sont susceptibles de changer un peu plus par rapport au JDK 13, je les comparerai donc plus tard.

Text Blocks

https://openjdk.java.net/jeps/368 Cela changera probablement un peu plus, mais je ne pense pas que cela changera beaucoup.

Java


    String s = """
	       ultra soul
	       OCEAN
	       """;
    System.out.println(s);
    // ultra soul
    // OCEAN

Kotlin


    val s = """
            ultra soul
            OCEAN
            """
    print(s)
    // ultra soul
    // OCEAN

C'est presque la même chose pour Java et Kotlin.

Comparer avec Java 14 ou version ultérieure

Eh bien, il n'est pas encore officiellement publié, mais comparons Kotlin à ce qui est en cours de développement.

Référence: Changements de syntaxe Java envisagés par Amber

Records(JEP 359)

Records prépare automatiquement du code tel que hashCode ʻequals`` toString`, qui est redondant dans les beans Java. C'est très simple et agréable.

Java


    record Point(int x, int y) {}

    Point point1 = new Point(5, 10);
    Point point2 = new Point(5, 10);
    System.out.println(point1.x());                   // 5
    System.out.println(point1);                       // Point[x=5, y=10]
    System.out.println(point1.equals(point2));        // true

Et Kotlin a une classe de données.

Kotlin


    data class Point(val x: Int, val y: Int)
    val point1 = Point(5, 10)
    val point2 = Point(5, 10)
    println(point1.x)                 // 5
    println(point1)                   // Point(x=5, y=10)
    println(point1.equals(point2))    // true

L'enregistrement semble faire référence à la classe de cas de Scala, à la classe de données de Kotlin, aux types d'enregistrement de C #, etc.

Sealed Types(JEP 360)

Les types scellés sont utilisés pour limiter l'héritage de classe Ceci est pratique à utiliser comme énumération.

Java


    sealed interface HondaCar {};

    public class Demio implements HondaCar {
        public String getName() {
            return "Demio";
        }
    }

    public class Vezel implements HondaCar {
        public String getName() {
            return "Vezel";
        }
    }

Kotlin


sealed class HondaCar
class Demio: HondaCar() {
    fun getName():String { return "Demio" }
}
class Vezel: HondaCar() {
    fun getName():String { return "Vezel" }
}

Basculer dans l'enregistrement

Je ne comprends pas beaucoup le code Java ici, mais j'écrirai une image. (Je me demande si j'ai vu un exemple d'utilisation de scellé / enregistrement avec commutateur quelque part, mais je n'ai pas encore trouvé de problème, donc si j'en trouve un, je vais coller l'URL détaillée)

Java


    // sealed
    sealed interface HondaCar permits Demio, Vezel {}
    record Demio() implements HondaCar {}
    record Vezel() implements HondaCar {}

    // use
    int price = switch(hondaCar) {
                    case Demio(int price) -> "Demio";
                    case Vezel(int price) -> "Vezel";
                    //Pas besoin de déclaration par défaut car scellé sait que les seules options sont Demio et Vezel
                    // default -> throw new IllegalStateException("Error");
                };

Kotlin est déjà disponible dans l'expression when.

Kotlin


    // sealed
    sealed class HondaCar
    class Demio: HondaCar()
    class Vezel: HondaCar()

    // use
   val hondaName = when(hondaCar) {
        is Demio -> "Demio"
        is Vezel -> "Vezel"
        //Aucune valeur par défaut requise
    }
    println(hondaName)

À propos, si vous n'utilisez pas de scellé avec Kotlin, la valeur par défaut (else) est requise.

Erreur Kotlin


    // interface
    interface NissanCar
    class Leaf: NissanCar
    class Juke: NissanCar

    // use
    val nissanCar: NissanCar = Leaf()
    val nissanName = when(nissanCar) {
        is Leaf -> "Leaf"
        is Juke -> "Juke"
        //Puisqu'il n'y a pas d'autre, l'erreur suivante est sortie
        // 'when' expression must be exhaustingstive, add necssary 'else' branch
    }
    println(nissanName)

Switch Expressions (JEP 361)

https://openjdk.java.net/jeps/361 À l'origine, je pensais que le commutateur Java était difficile à utiliser, mais il a été envisagé depuis JDK12 (JEP 325), et il semble que diverses améliorations aient été apportées. Je veux juste le comparer avec Kotlin, donc je ne décrirai que les parties qui changent de manière significative.

Plusieurs cas qui s'inscrivent dans le même bloc peuvent être décrits en même temps

Java


    //à l'origine
    switch (day) {
        case MONDAY:
        case FRIDAY:
        case SUNDAY:
            System.out.println(6);
            break;
        case TUESDAY:
            System.out.println(7);
            break;
    }

    //Après amélioration
    switch (day) {
        case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
        case TUESDAY                -> System.out.println(7);
        case THURSDAY, SATURDAY     -> System.out.println(8);
        case WEDNESDAY              -> System.out.println(9);
    }

Plusieurs Kotlins peuvent être répertoriés en même temps.

Kotlin


    when (day) {
        Day.MONDAY, Day.FRIDAY, Day.SUNDAY -> println(6)
        Day.TUESDAY -> println(7)
        Day.THURSDAY,  Day.SATURDAY -> println(8)
        Day.WEDNESDAY -> println(9)
    }

switch peut être utilisé comme expression

Comme mentionné dans Types scellés, il semble que le résultat de switch puisse être utilisé comme expression et stocké dans une variable. Actuellement, lors de l'utilisation de switch dans une boucle telle qu'une instruction for, il semble que le mouvement de pause et continue soit ajusté.

Java


    int j = switch (day) {
        case MONDAY  -> 0;
        case TUESDAY -> 1;
        default      -> {
            int k = day.toString().length();
            int result = f(k);
            yield result;
        }
    };

Kotlin


    val j = when (day) {
        is Monday -> 0;
        is Tuesday -> 1;
        else -> {
            val k = day.toString().length
            k
        }
    }

    //Kotlin prend également en charge la pause et la poursuite du commutateur(C'est une logique inutile)
    loop@ for (i in 1..100) {
        when (day) {
            is Monday -> j = 0;
            is Tuesday -> j = 1;
            else -> {
                j = day.toString().length
                break@loop
            }
        }
    }

Pattern Matching for instanceof (JEP 305)

Après avoir vérifié le type avec instanceof, le type est fixe, donc Pattern Matching for instanceof peut être utilisé en le stockant dans une variable telle quelle.

Java


    //jusqu'à maintenant
    if (o instanceof String) {
        //Vous ne pouvez pas utiliser o directement comme type de chaîne
        // System.out.println(o.length());

        //Il est nécessaire de le convertir une fois en type String, puis de l'utiliser
        String s = (String)o;
        System.out.println(s.length());     // 27
    }

    //à partir de maintenant
    Object o = "Pattern Match of instanceof";
    //Peut être stocké dans une variable en même temps que instanceof
    if (o instanceof String s) {
        System.out.println(s.length());    // 27
    }

    //Il semble que le commutateur sera également disponible.(OpenJDK 14 Early-Toujours dans Access Build 25)
    // https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html
    switch (o) {
        case Integer i -> System.out.println(i);
        case String s -> System.out.println(s.length());
    }

Kotlin peut être utilisé tel quel sans le stocker dans une variable.

Kotlin


    val o: Any = "Pattern Match of instanceof"
    if (o is String) {
        println(o.length)    // 27
    }
    when(o) {
        is Int -> println("Int")
        is String -> {
            val s:String = o
            println(s)
        }
    }
    // 27

Résumé

Tout d'abord, j'ai trouvé incroyable que Java ait autant évolué.

Auparavant, Kotlin était le meilleur. Je pense que Java était une image décevante, mais j'ai l'impression que Java a également adopté des langages modernes comme Kotlin vers JDK17, et la différence est en train de disparaître. Et j'ai été surpris par Kotlin, qui a déjà adopté une telle nouvelle syntaxe Java.

Du point de vue de la comparaison des langages entre Java et Kotlin, Kotlin a toujours des avantages tels que la sécurité NULL et l'écriture facile des types de fonctions, et à partir de septembre 2021, lorsque le prochain LTS, JDK17, sera publié, lequel Je me suis demandé si je pouvais le choisir.

J'écrirai à Kotlin pour le nouveau projet que je vais faire, donc j'aimerais écrire un article séparé sur ce qui m'intéressait tout en m'en occupant à l'avenir.

finalement

C'est le reflet que la couleur de Java est devenue plus forte même s'il s'agit d'une publicité de Kotlin.

De plus, je suis désolé que ce soit devenu une expression selon laquelle d'autres personnes réutilisent le contenu déjà dans l'article. Pour la comparaison entre Kotlin et le nouveau Java, il y avait beaucoup de contenu dont j'ai inévitablement souffert même s'il y avait peu d'informations, alors pardonnez-moi.

J'ai réfléchi en écrivant, mais il semble préférable de comparer également JDK9 à JDK11. Nous vous répondrons lorsque vous pourrez vous le permettre.

Kotlin ne l'a pas touché dans les affaires pour le moment, donc je pense qu'il y a certaines parties que je ne comprends pas, alors j'aimerais le corriger progressivement à mesure que ma compréhension s'approfondit.

Informations de référence

Résumé des nouvelles fonctionnalités de Java 12 Changements de syntaxe Java envisagés par Amber

https://openjdk.java.net/projects/jdk/13/ https://openjdk.java.net/projects/amber/

Recommended Posts