JavaRush /Blog Java /Random-FR /Pause café #165. Packages en Java. Méthodes thread-safe p...

Pause café #165. Packages en Java. Méthodes thread-safe pour les débutants

Publié dans le groupe Random-FR

Paquets Java

Source : Usemynotes Cet article vous aidera à mieux comprendre les packages en Java, à comprendre leur objectif et comment les implémenter. Pause café #165.  Packages en Java.  Méthodes thread-safe pour les débutants - 1

Que sont les packages en Java

Un package en Java est un moyen de regrouper un groupe de classes, d'interfaces et de sous-packages. Les packages sont utilisés pour créer des groupes de classes, d'interfaces, d'énumérations associées, etc. Les sous-packages sont des packages qui se trouvent dans un autre package. Ils ne sont pas importés par défaut, mais vous pouvez les importer manuellement si nécessaire. La spécification d'accès n'est pas fournie aux membres individuels d'un sous-paquet ; ils sont traités comme des packages distincts.

Quelques types de packages en Java :

  • java.lang - est fourni avec Java par défaut.
  • java.io - contient des classes, des méthodes et d'autres éléments liés aux entrées/sorties.

Pourquoi les forfaits sont-ils nécessaires ?

  • Pour éviter les conflits de noms.
  • Pour fournir un accès contrôlé.
  • Pour réaliser l’encapsulation des données.

Comment créer un package en Java ?

Créons un package appelé ordinateur . Généralement, le nom du package est écrit en lettres minuscules. Ceci est fait uniquement pour éviter les conflits de noms avec les noms de classe. Nous créerons également une interface appelée Pluggable , qui sera située dans le package informatique .
package computer;

interface Pluggable {
   public void pluggedIn();
   public void pluggedOut();
}
Nous allons maintenant créer une classe appelée PenDrive qui implémentera l'interface ci-dessus.
package computer;

public class PenDrive implements Pluggable {

   int storage = 64;

   public void pluggedIn () {
     System.out.println("Pen Drive is connected");
   }

   public void pluggedOut () {
     System.out.println("Pen Drive is removed");
   }

   public int storage() {
     return storage;
   }

   public static void main(String args[]) {
     PenDrive p = new PenDrive ();
     p.pluggedIn();
     System.out.println("Pen Drive Storage: " + p.storage());
     p.pluggedOut();
   }
}

Comment créer une hiérarchie de packages en Java ?

Lors de la formation d'une hiérarchie, les packages en Java sont nommés dans l'ordre inverse. Cela les rend très similaires aux répertoires ou aux dossiers. Tout comme sur un ordinateur personnel, où un dossier peut contenir un ou plusieurs sous-dossiers, il en va de même pour les packages Java. Regardons un package nommé Asia.India.Kolkata . Ce sont tous des dossiers existants, mais si l’on considère la géographie, il est clair que Calcutta est en Inde et que l’Inde est en Asie. L’objectif principal d’une hiérarchie est de faciliter la recherche des classes.

Types de packages en Java

Forfaits intégrés

Les packages intégrés sont des packages constitués d'un grand nombre de classes intégrées qui font partie de l'API Java. Ces forfaits comprennent :
  • java.util - Ce package contient un nombre fini de classes utilitaires utilisées pour implémenter des structures de données telles que des listes chaînées, des ensembles, etc. Il prend également en charge les opérations de date et d'heure et bien plus encore.
  • java.net - Il contient des classes utilisées pour les opérations réseau.

Packages définis par l'utilisateur

Les packages définis par l'utilisateur sont appelés packages utilisateur. L'utilisateur peut créer manuellement un package et contenir autant de classes qu'il le souhaite.

Comment accéder à un package depuis un autre package ?

Vous pouvez accéder à un package à partir d’un autre package de trois manières simples :
  • Utiliser un astérisque dans une instruction d'importation
Le caractère astérisque ( * ) est utilisé pour représenter « toutes choses » en Java. En l'utilisant, nous pouvons importer tout ce qui se trouve dans un sous-paquet d'un package. Exemple : considérons un package nommé tools . Si nous voulons importer tout ce qui se trouve dans ce package, nous devons utiliser l'instruction d'importation telle que :
import tools.*;
  • Utilisation de l'importation package.ClassName ;
Mentionner le nom de la classe dans un package est un moyen efficace d'importer uniquement les classes dont vous avez besoin dans votre programme, évitant ainsi d'importer des classes inutiles. Exemple : considérons un package nommé books . Si nous souhaitons uniquement importer une classe ou une interface spécifique à partir de celle-ci (nous examinerons la classe Pages ), nous pouvons importer uniquement cela en utilisant :
import book.Pages;
  • En utilisant votre nom complet
Il existe un moyen d'utiliser directement un package Java ou ses classes en utilisant leur nom complet. De cette façon, vous n'avez pas besoin d'importer le package et pouvez l'utiliser directement dans le programme. Exemple:
java.awt.List aSimpleList = new java.awt.List();

Taille de lot par défaut en Java

Par défaut, Java importe le package java.lang . Il contient de nombreuses classes couramment utilisées dans des programmes Java simples tels que String , Integer et autres. L'une des classes les plus importantes est la classe Object , qui se trouve également dans le package java.lang . La taille de ce package est basée sur ses composants : 8 interfaces, 37 classes, 3 énumérations, 27 exceptions, 23 types d'erreurs et 5 types d'annotations.

Méthodes Java Thread-Safe pour les débutants

Source : Medium Grâce à cet article, vous pouvez en apprendre davantage sur le fonctionnement des méthodes thread-safe en Java. Pause café #165.  Packages en Java.  Méthodes thread-safe pour les débutants - 2J'ai constaté que de nombreux développeurs Java juniors/moyens comprennent mal comment les méthodes thread-safe devraient fonctionner dans des projets réels. Et comme nous travaillons généralement dans un environnement multithread, leur utilisation correcte est très importante. Une méthode thread-safe est une méthode qui peut être appelée simultanément à partir de plusieurs threads sans affecter l’état des données de chacun. Une compréhension insuffisante de ce concept conduit à des bugs difficiles à trouver et à corriger. Pour éviter de telles erreurs, regardons des exemples.

Exemple 1:

public static int countLetters(String input) {
    int counter = 0;

    for (Character c : input.toCharArray()) {
        if (Character.isAlphabetic(c)) {
            counter++;
        }
    }

    return counter;
}
  • La méthode countLetters est statique, elle renvoie une valeur int et accepte un paramètre chaîne en entrée.
  • Un compteur de variable primitif est créé à l'intérieur de la méthode, puis la boucle parcourt les caractères de la chaîne d'entrée et incrémente le compteur de variable à chaque fois qu'un caractère de lettre est rencontré.
Cette méthode est-elle thread-safe ? De nombreux développeurs disent non, car dans ce cas, nous avons une opération d'incrémentation qui n'est pas thread-safe. Voyons cela. Dans le modèle de mémoire Java, nous avons une pile et un tas. Chaque thread possède sa propre pile et tous les threads partagent le même tas. À cet égard, les données de la pile sont toujours thread-safe, mais pas les données du tas. La pile stocke les primitives et les références d'objets. Le tas contient les objets eux-mêmes. Cela signifie que dans cet exemple de code, chaque thread stocke son propre compteur de variables sur la pile et n'a aucun effet sur les données des autres threads, la méthode est donc thread-safe . Notez que la valeur String d'entrée est également un objet, mais les wrappers String et primitifs ( Integer , Long , Double , Boolean et ainsi de suite) sont thread-safe car ils sont immuables.

Exemple n°2 :

public static int countLetters2(String input) {
    List<Character> listCounter = new ArrayList<>();

    for (Character c : input.toCharArray()) {
        if (Character.isAlphabetic(c)) {
            listCounter.add(c);
        }
    }

    return listCounter.size();
}
Ce code utilisait la même logique que le premier exemple, mais utilisait un objet List au lieu d'une variable int primitive . De la partie précédente, nous savons que les objets en Java sont stockés dans un tas et que List est un objet. Nous savons également que la pile stocke les références aux objets sur le tas. Dans l'exemple n°2, chaque thread crée un nouvel objet ArrayList : et la variable listCounter stocke une référence à son objet sur le tas, donc aucun autre thread ne peut modifier cet objet.
List<Character> listCounter = new ArrayList<>();
Cela signifie que cette méthode est thread-safe.

Exemple n°3 :

public class CounterUtil { // singleton

    List<Character> listCounter = new ArrayList<>();

    public int countLetters3(String input) {
        for (Character c : input.toCharArray()) {
            if (Character.isAlphabetic(c)) {
                listCounter.add(c);
            }
        }

        return listCounter.size();
    }
}
Dans cet exemple, nous avons une classe singleton (c'est important) CounterUtil avec une variable globale listCounter . Cette variable est créée en même temps que l'instance singleton. Lorsque plusieurs threads appellent la méthode countChars3 , ils utilisent tous la même variable globale listCounter , qui stocke une référence au même objet sur le tas, et les threads s'influenceront mutuellement. Nous pouvons donc conclure que cette méthode n’est pas thread-safe. Et même si nous changeons List<Character> listCounter en une variable primitive int counter , elle ne sera pas non plus thread-safe car tous les threads utiliseront la même variable primitive.

Dernier exemple :

public static int countLetters4(List<Character> inputList) {
    List<Character> listCounter = new ArrayList<>();

    for (Character c : inputList) {
        if (Character.isAlphabetic(c)) {
            listCounter.add(c);
        }
    }

    return listCounter.size();
}
La méthode countLetters4 accepte une liste de caractères au lieu d'un paramètre String . Ici, nous ne pouvons pas garantir que cette méthode est thread-safe. Pourquoi? Parce que nous ne pouvons pas être sûrs de la manière dont les développeurs utiliseront cette méthode. Si un autre thread extérieur modifie les données dans inputList en même temps que notre méthode counterLetters4 , cela pourrait affecter le résultat final.

Conclusion

Nous n'avons examiné que quatre exemples, et ils ne couvrent pas tous les aspects de la sécurité des threads dans les projets Java, mais ils constituent un bon point de départ. La prochaine fois que vous verrez une méthode dans votre code, demandez-vous : « Cette méthode est-elle thread-safe ? » Et très bientôt, vous comprendrez clairement la réponse.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION