JavaRush /Blog Java /Random-FR /Du 8 au 13 : un aperçu complet des versions Java. Partie ...

Du 8 au 13 : un aperçu complet des versions Java. Partie 1

Publié dans le groupe Random-FR
Chatons, bonjour à tous)) Donc, aujourd'hui, nous sommes en 2020, et il reste très peu de choses avant la sortie de Java 14. Vous devriez vous attendre à la version finale le 17 mars, nous analyserons ce qui y est nouveau et intéressant après coup, mais aujourd'hui j'aimerais me rafraîchir la mémoire sur les versions précédentes de Java. Que nous ont-ils apporté de nouveau ? Jetons un coup d'oeil. Commençons la revue par Java 8, car il est toujours assez pertinent et est utilisé dans la plupart des projets. Du 8 au 13 : un aperçu complet des versions Java.  Partie 1 - 1Auparavant, de nouvelles versions étaient publiées tous les 3 à 5 ans, mais récemment, Oracle a adopté une approche différente : « un nouveau Java tous les six mois ». Ainsi, tous les six mois, nous assistons à la sortie de fonctionnalités. Que ce soit bon ou mauvais, chacun le voit différemment. Par exemple, je n'aime pas beaucoup ça, car les nouvelles versions n'ont pas beaucoup de nouvelles fonctionnalités, mais en même temps, les versions poussent comme des champignons après la pluie. J'ai cligné des yeux plusieurs fois sur un projet avec Java 8, et Java 16 était déjà sorti (mais quand il sort rarement, les nouvelles fonctionnalités s'accumulent, et au final cet événement est très attendu, comme des vacances : tout le monde discute du de nouveaux goodies et vous ne pouvez pas passer à côté) . Alors, commençons!

Java8

Interface fonctionnelle

Qu'est-ce que c'est? Une interface fonctionnelle est une interface qui contient une méthode (abstraite) non implémentée. @FunctionalInterface est une annotation facultative placée au-dessus d'une telle interface. Nécessaire pour vérifier s'il répond aux exigences d'une interface fonctionnelle (n'ayant qu'une seule méthode abstraite). Mais comme toujours, nous avons quelques réserves : les méthodes par défaut et statiques ne répondent pas à ces exigences. Par conséquent, il peut y avoir plusieurs méthodes de ce type + une abstraite, et l'interface sera fonctionnelle. Il peut également contenir des méthodes de la classe Object qui n'affectent pas la définition de l'interface comme fonctionnelle. J'ajouterai quelques mots sur les méthodes par défaut et statiques :
  1. Les méthodes avec le modificateur par défaut vous permettent d'ajouter de nouvelles méthodes aux interfaces sans interrompre leur implémentation existante.

    public interface Something {
      default void someMethod {
          System.out.println("Some text......");
      }
    }

    Oui, oui, nous ajoutons la méthode implémentée à l'interface, et lors de l'implémentation de cette méthode, vous ne pouvez pas la remplacer, mais l'utiliser comme une méthode héritée. Mais si une classe implémente deux interfaces avec une méthode donnée, nous aurons une erreur de compilation, et si elle implémente des interfaces et hérite d'une classe avec une certaine méthode identique, la méthode de la classe parent chevauchera les méthodes d'interface et l'exception ne fonctionnera pas.

  2. les méthodes statiques d’une interface fonctionnent de la même manière que les méthodes statiques d’une classe. N'oubliez pas : vous ne pouvez pas hériter de méthodes statiques , tout comme vous ne pouvez pas appeler une méthode statique à partir d'une classe descendante.

Alors encore quelques mots sur les interfaces fonctionnelles et passons à autre chose. Voici les principales listes d'IF (le reste sont leurs variétés) :

    Prédicat - prend une valeur T comme argument, renvoie un booléen.

    Exemple:boolean someMethod(T t);

  • Consommateur - prend un argument de type T, ne renvoie rien (vide).

    Exemple:void someMethod(T t);

  • Fournisseur - ne prend rien en entrée, mais renvoie une valeur T.

    Exemple:T someMethod();

  • Fonction - prend un paramètre de type T en entrée, renvoie une valeur de type R.

    Exemple:R someMethod(T t);

  • UnaryOperator - prend un argument T et renvoie une valeur de type T.

    Exemple:T someMethod(T t);

Flux

Les flux sont un moyen de gérer les structures de données dans un style fonctionnel. Il s'agit généralement de collections (mais vous pouvez les utiliser dans d'autres situations moins courantes). Dans un langage plus compréhensible, Stream est un flux de données que nous traitons comme si nous travaillions avec toutes les données en même temps, et non par force brute, comme pour chaque. Regardons un petit exemple. Disons que nous avons un ensemble de nombres que nous voulons filtrer (moins de 50), augmenter de 5 et afficher les 4 premiers nombres des nombres restants sur la console. Comment aurions-nous fait cela plus tôt :
List<Integer> list = Arrays.asList(46, 34, 24, 93, 91, 1, 34, 94);

int count = 0;

for (int x : list) {

  if (x >= 50) continue;

  x += 5;

  count++;

  if (count > 4) break;

  System.out.print(x);

}
Il ne semble pas y avoir beaucoup de code et la logique est déjà un peu déroutante. Voyons à quoi cela ressemblera en utilisant le flux :
Stream.of(46, 34, 24, 93, 91, 1, 34, 94)

      .filter(x -> x < 50)

      .map(x -> x + 5)

      .limit(4)

      .forEach(System.out::print);
Les flux simplifient grandement la vie en réduisant la quantité de code et en le rendant plus lisible. Pour ceux qui souhaitent approfondir ce sujet, voici un bon (je dirais même excellent) article sur ce sujet .

Lambda

La fonctionnalité la plus importante et la plus attendue est peut-être l’apparition des lambdas. Qu’est-ce que lambda ? Il s'agit d'un bloc de code qui peut être transmis à différents endroits afin de pouvoir être exécuté ultérieurement autant de fois que nécessaire. Cela semble assez déroutant, n'est-ce pas ? En termes simples, en utilisant lambdas, vous pouvez implémenter une méthode d'interface fonctionnelle (une sorte d'implémentation d'une classe anonyme) :
Runnable runnable = () -> { System.out.println("I'm running !");};

new Thread(runnable).start();
Nous avons implémenté la méthode run() rapidement et sans formalités administratives inutiles. Et oui : Runnable est une interface fonctionnelle. J'utilise également des lambdas lorsque je travaille avec des flux (comme dans les exemples avec des flux ci-dessus). Nous n’irons pas trop loin, puisque nous pouvons plonger assez profondément, je vais laisser quelques liens pour que les gars qui sont encore des creuseurs dans l’âme puissent creuser plus profondément :

pour chaque

Java 8 a un nouveau foreach qui fonctionne avec un flux de données comme un flux. Voici un exemple :
List<Integer> someList = Arrays.asList(1, 3, 5, 7, 9);

someList.forEach(x -> System.out.println(x));
(analogue à someList.stream().foreach(…))

Référence de la méthode

Les méthodes de référence sont une nouvelle syntaxe utile conçue pour référencer des méthodes ou des constructeurs existants de classes ou d'objets Java via : : Les références de méthode sont de quatre types :
  1. Lien vers le concepteur :

    SomeObject obj = SomeObject::new

  2. Référence de méthode statique :

    SomeObject::someStaticMethod

  3. Une référence à une méthode non statique d'un objet d'un certain type :

    SomeObject::someMethod

  4. Une référence à une méthode régulière (non statique) d'un objet spécifique

    obj::someMethod

Souvent, les références de méthodes sont utilisées dans les flux au lieu des lambdas (les méthodes de référence sont plus rapides que les lambdas, mais sont moins lisibles).
someList.stream()

        .map(String::toUpperCase)

      .forEach(System.out::println);
Pour ceux qui souhaitent plus d’informations sur les méthodes de référence :

Heure de l'API

Il existe une nouvelle bibliothèque pour travailler avec les dates et les heures - java.time. Du 8 au 13 : un aperçu complet des versions Java.  Partie 1 - 2La nouvelle API est similaire à n'importe quel Joda-Time. Les sections les plus importantes de cette API sont :
  • LocalDate est une date spécifique, par exemple - 2010-01-09 ;
  • LocalTime - heure prenant en compte le fuseau horaire - 19:45:55 (analogue à LocalDate) ;
  • LocalDateTime - combo LocalDate + LocalTime - 04/01/2020 15:37:47 ;
  • ZoneId - représente les fuseaux horaires ;
  • Horloge - en utilisant ce type, vous pouvez accéder à l'heure et à la date actuelles.
Voici quelques articles vraiment intéressants sur ce sujet :

Facultatif

Il s'agit d'une nouvelle classe dans le package java.util , un wrapper de valeur dont l'astuce est qu'il peut également contenir null en toute sécurité . Réception facultative : si nous passons nullOptional<String> someOptional = Optional.of("Something"); dans Option.of , nous obtiendrons notre NullPointerException préférée . Pour de tels cas, ils utilisent : - dans cette méthode, vous n'avez pas à avoir peur de null. Ensuite, créez un élément initialement vide. Facultatif : Pour vérifier s'il est vide, utilisez : nous renverra vrai ou faux. Effectuer une certaine action s'il y a une valeur, et ne rien faire s'il n'y a pas de valeur : Une méthode inverse qui renvoie la valeur passée si Facultatif est vide (sorte de plan de sauvegarde) : Vous pouvez continuer pendant très, très longtemps ( heureusement, Optionnel a ajouté des méthodes avec des mains généreuses), mais nous ne nous attarderons pas là-dessus. Il vaut mieux que je laisse quelques liens pour commencer : Optional<String> someOptional = Optional.ofNullable("Something");Optional<String> someOptional = Optional.empty();someOptional.isPresent();someOptional.ifPresent(System.out::println);System.out.println(someOptional.orElse("Some default content")); Nous avons passé en revue les innovations les plus célèbres de Java 8 - ce n'est pas tout. Si vous voulez en savoir plus, je vous laisse ceci :

Java9

Ainsi, le 21 septembre 2017, le monde a vu JDK 9. Ce Java 9 est livré avec un riche ensemble de fonctionnalités. Bien qu’il n’y ait pas de nouveaux concepts de langage, les nouvelles API et commandes de diagnostic intéresseront certainement les développeurs. Du 8 au 13 : un aperçu complet des versions Java.  Partie 1 à 4

JShell (REPL - boucle lecture-évaluation-impression)

Il s'agit d'une implémentation Java d'une console interactive utilisée pour tester les fonctionnalités et utiliser différentes constructions dans la console, telles que des interfaces, des classes, des énumérations, des opérateurs, etc. Pour lancer JShell, il vous suffit d'écrire jshell dans le terminal. Nous pouvons ensuite écrire tout ce que notre imagination nous permet : Du 8 au 13 : un aperçu complet des versions Java.  Partie 1 à 5en utilisant JShell, vous pouvez créer des méthodes de haut niveau et les utiliser au sein de la même session. Les méthodes fonctionneront comme les méthodes statiques, sauf que le mot clé static peut être omis. Pour en savoir plus, consultez le manuel Java 9. REPL (JShell) .

Privé

À partir de la version 9 de Java, nous avons la possibilité d'utiliser des méthodes privées dans les interfaces (méthodes par défaut et statiques, car nous ne pouvons tout simplement pas en écraser d'autres en raison d'un accès insuffisant). private static void someMethod(){} try-with-resources La capacité de gérer les exceptions Try-With-Resources a été améliorée :
BufferedReader reader = new BufferedReader(new FileReader("....."));
  try (reader2) {
  ....
}

Modularité ( puzzle )

Un module est un groupe de packages et de ressources associés ainsi qu'un nouveau fichier descripteur de module. Cette approche est utilisée pour desserrer le couplage du code. Le couplage lâche est un facteur clé pour la maintenabilité et l’extensibilité du code. La modularité est mise en œuvre à différents niveaux :
  1. Langage de programmation.
  2. Machine virtuelle.
  3. API Java standard.
JDK 9 est livré avec 92 modules : nous pouvons les utiliser ou créer les nôtres. Voici quelques liens pour un aperçu plus approfondi :

Collection immuable

En Java 9, il est devenu possible de créer et de remplir une collection avec une seule ligne, tout en la rendant immuable (auparavant, pour créer une collection immuable, il fallait créer une collection, la remplir de données et appeler une méthode, par exemple : Collections.unmodifiableList). Un exemple d'une telle création : List someList = List.of("first","second","third");

Autres nouveautés :

  • étendu Facultatif (nouvelles méthodes ajoutées) ;
  • les interfaces ProcessHandle et ProcessHandle semblaient contrôler les actions du système d'exploitation ;
  • G1 - garbage collector par défaut ;
  • Client HTTP prenant en charge les protocoles HTTP/2 et WebSocket ;
  • Flux étendu ;
  • ajout du framework API Reactive Streams (pour la programmation réactive) ;
Pour une immersion plus complète dans Java 9, je vous conseille de lire :

Java10

Ainsi, six mois après la sortie de Java 9, en mars 2018 (je m'en souviens comme hier), Java 10 est entré en scène. Du 8 au 13 : un aperçu complet des versions Java.  Partie 1 à 6

var

Désormais, nous n'avons plus besoin de fournir de type de données. Nous marquons le message comme var et le compilateur détermine le type du message par le type de l'initialiseur présent à droite. Cette fonctionnalité n'est disponible que pour les variables locales avec un initialiseur : elle ne peut pas être utilisée pour les arguments de méthode, les types de retour, etc., puisqu'il n'y a pas d'initialiseur pour pouvoir définir le type. Exemple var (pour le type String) :
var message = "Some message…..";
System.out.println(message);
var n'est pas un mot-clé : c'est essentiellement un nom de type réservé, tout comme int . L'avantage de var est grand : les déclarations de type nécessitent beaucoup d'attention sans apporter aucun avantage, et cette fonctionnalité permettra de gagner du temps. Mais en même temps, si une variable est obtenue à partir d'une longue chaîne de méthodes, le code devient moins lisible, car on ne sait pas immédiatement quel type d'objet s'y trouve. Dédié à ceux qui souhaitent se familiariser avec cette fonctionnalité :

Compilateur JIT (GraalVM)

Sans plus tarder, permettez-moi de vous rappeler que lorsque vous exécutez la commande javac, l'application Java est compilée à partir du code Java vers le bytecode JVM, qui est la représentation binaire de l'application. Mais un processeur informatique classique ne peut pas simplement exécuter le bytecode JVM. Pour que votre programme JVM fonctionne, vous avez besoin d'un autre compilateur pour ce bytecode, qui est converti en code machine que le processeur est déjà capable d'utiliser. Comparé à javac, ce compilateur est beaucoup plus complexe, mais produit également un code machine de meilleure qualité. Actuellement, OpenJDK contient la machine virtuelle HotSpot, qui possède à son tour deux compilateurs JIT principaux. Le premier, C1 ( compilateur client ), est conçu pour un fonctionnement à plus grande vitesse, mais l'optimisation du code en souffre. Le second est C2 (compilateur serveur). La vitesse d'exécution en souffre, mais le code est plus optimisé. Quand est-ce qu'on utilise lequel ? C1 est idéal pour les applications de bureau où les longues pauses JIT ne sont pas souhaitables, et C2 est idéal pour les programmes serveur de longue durée où consacrer plus de temps à la compilation est tout à fait supportable. La compilation multi-niveaux se produit lorsque la compilation passe d'abord par C1 et que le résultat passe par C2 (utilisé pour une plus grande optimisation). GraalVM est un projet créé pour remplacer complètement HotSpot. Nous pouvons considérer Graal comme plusieurs projets liés : un nouveau compilateur JIT pour HotSpot et une nouvelle machine virtuelle polyglotte. La particularité de ce compilateur JIT est qu'il est écrit en Java. L'avantage du compilateur Graal est la sécurité, c'est-à-dire pas de crash, mais d'exceptions, pas de fuites de mémoire. Nous aurons également un bon support IDE et nous pourrons utiliser des débogueurs, des profileurs ou d'autres outils pratiques. De plus, le compilateur pourrait bien être indépendant de HotSpot et il sera capable de créer une version plus rapide de lui-même, compilée en JIT. Pour les creuseurs :

Parallèle G1

Le garbage collector G1 est certes cool, sans aucun doute, mais il a aussi un point faible : il effectue un cycle GC complet monothread. À une époque où vous avez besoin de toute la puissance matérielle possible pour trouver les objets inutilisés, nous sommes limités à un seul thread. Ce problème a été corrigé dans Java 10. Désormais, le GC fonctionne désormais avec toutes les ressources que nous y ajoutons (c'est-à-dire qu'il devient multithread). Pour y parvenir, les développeurs du langage ont amélioré l'isolation des principales sources de GC, créant ainsi une interface claire et agréable pour GC. Les développeurs de cette gentillesse, OpenJDK, ont dû nettoyer spécifiquement le dump dans le code afin non seulement de simplifier au maximum la création de nouveaux GC, mais également de permettre de désactiver rapidement les GC inutiles de l'assembly. L’un des principaux critères de réussite est l’absence de baisse de vitesse de fonctionnement après toutes ces améliorations. Regardons aussi : Autres nouveautés :
  1. Une interface propre de Garbage-Collector est introduite. Cela améliore l'isolation du code source des différents garbage collectors, permettant d'intégrer des collecteurs alternatifs rapidement et sans douleur ;
  2. Combiner les sources JDK dans un seul référentiel ;
  3. Les collections ont reçu une nouvelle méthode - copyOf (Collection) , qui renvoie une copie immuable de cette collection ;
  4. Facultatif (et ses variantes) a une nouvelle méthode .orElseThrow() ;
  5. Désormais, les JVM savent qu'elles s'exécutent dans un conteneur Docker et récupèreront la configuration spécifique au conteneur plutôt que d'interroger le système d'exploitation lui-même.
Voici quelques documents supplémentaires pour une introduction plus détaillée à Java 10 : J'étais très confus par le fait que certaines versions de Java s'appelaient 1.x. Je voudrais être clair : les versions Java antérieures à 9 avaient simplement un schéma de dénomination différent. Par exemple, Java 8 peut également être appelé 1.8 , Java 5 - 1.5 , etc. Et maintenant, nous voyons qu'avec la transition vers les versions de Java 9, le schéma de dénomination a également changé et les versions Java ne sont plus préfixées par 1.x . C'est la fin de la première partie : nous avons passé en revue les nouvelles fonctionnalités intéressantes de Java 8-10. Continuons notre connaissance des dernières nouveautés dans le prochain post .
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION