JavaRush /Blog Java /Random-FR /Top 50 des questions et réponses d'entretien avec Java Co...
Roman Beekeeper
Niveau 35

Top 50 des questions et réponses d'entretien avec Java Core. Partie 2

Publié dans le groupe Random-FR
Top 50 des questions et réponses d'entretien avec Java Core. Partie 1 Top 50 des questions et réponses d'entretien avec Java Core.  Partie 2 - 1

Collections

25. Qu’entend-on par collections en Java ?

Collection est un framework conçu pour stocker et manipuler des objets. Utilisé pour effectuer les opérations suivantes :
  • recherche;
  • tri;
  • manipulation;
  • ajout;
  • effacement.
Toutes les classes et interfaces du framework Collection sont dans java.utille package.

26. Quelles classes et interfaces sont disponibles dans le framework Collection ?

Interfaces :
  • Collection;
  • Liste;
  • Ensemble;
  • Carte;
  • Ensemble trié ;
  • Carte triée ;
  • File d'attente.
Des classes:
  • Listes:
    1. Liste des tableaux;
    2. Liste liée ;
    3. Vecteur (obsolète).
  • Ensembles :
    1. Ensemble de hachage ;
    2. LinkedHashSet ;
    3. TreeSet.
  • Plans:
    1. Carte de hachage
    2. ArbreCarte
    3. Table de hachage (obsolète)
    4. LinkedHashMap
  • File d'attente
    1. File d'attente de priorité.

27. Qu'entend-on par triés et ordonnés dans les collections ?

Commandé:

Cela signifie que les éléments stockés dans la collection sont basés sur les valeurs ajoutées à la collection. De cette façon, nous pouvons parcourir les valeurs de la collection dans un ordre spécifique. En d’autres termes, cela signifie que les éléments de la collection ont leur propre ordre spécifique selon lequel ils sont disposés. Pour une meilleure compréhension, une collection non ordonnée stocke ses éléments dans un ordre aléatoire. Par exemple, Définir.

Trié :

Cela signifie qu'un groupe d'éléments est trié dans une collection en fonction des données de l'élément de collection. Autrement dit, non seulement la collection est ordonnée, mais l'ordre des éléments dépend également de leurs valeurs. Cet ordre peut changer si vous triez selon une valeur d'élément différente.

28. Quelles collections existe-t-il avec une interface List ? Comment travaillez-vous avec List ?

Les valeurs des éléments d'une feuille sont basées sur leur index : elles sont classées par index. Les répétitions d'éléments sont autorisées (c'est-à-dire que vous pouvez ajouter le même objet à la collection plusieurs fois et tout ira bien).

Liste des tableaux:

La collection la plus courante. Il s’agit essentiellement d’un tableau dont la taille s’étend de manière dynamique. Le travail de gestion de la taille du tableau incombe à la collection. Il est important pour nous de comprendre que dans la plupart des cas, c'est ce que nous devons utiliser. Particularités :
  • recherche rapide et recherche d'index rapide ;
  • la collection est classée par index, mais pas triée ;
  • implémente l'interface RandomAccess ;
  • s'ajoutant lentement au milieu de la liste.
Exemple:
public class A {

   public static void main(String[] args) {
       ArrayList names = new ArrayList<>();
       names.add("John");
       names.add("John");
       names.add("Roman");
       names.add("Ivan");
   }

}
>> sortie

   [John, John, Roman, Ivan]
Le résultat montre qu’il s’agit d’éléments reproductibles. Ils sont affichés dans l'ordre dans lequel ils ont été enregistrés. Que lire d'autre ? Oui, il y a beaucoup d’informations, vous n’avez même pas besoin de quitter JavaRush :

Liste liée :

Il s'agit d'une collection dans laquelle chaque élément a un lien vers les éléments précédents et suivants. Ces liens permettent de passer d'un élément à un autre. Lors de l'ajout d'un élément, les liens vers les éléments précédents et suivants changent simplement : Top 50 des questions et réponses d'entretien avec Java Core.  Partie 2 - 2
  • les éléments sont connectés les uns aux autres, c'est-à-dire qu'une liste doublement chaînée est implémentée ;
  • la vitesse globale de fonctionnement est sensiblement inférieure à celle d'ArrayList ;
  • un excellent choix pour un grand nombre d'insertions et de suppressions au milieu d'un tableau ;
  • implémente les interfaces Queue et Deque list, et dispose donc de ses méthodes de travail.
Exemple:
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("One");
linkedList.add("Two");
linkedList.add("Three");

29. Parlez-nous de la collection Map et de ses implémentations ?

La carte est une collection clé-valeur. Il existe une clé unique et une valeur qui correspond à cette valeur. equals()Des méthodes sont également utilisées hashcode()pour déterminer le caractère unique d’une clé.

Carte de hachage :

  • non trié ou ordonné ;
  • utilisé si l'ordre et le tri ne sont pas importants ;
  • prend en charge la clé nulle.
Exemple:
public class CollectionExample {

   public static void main(String[] args) {
       HashMap positions = new HashMap<>();
       positions.put("junior", "Ivan");
       positions.put("middle", "Roman");
       positions.put("senior", "Vasily");
       positions.put("team lead", "Anton");
       positions.put("arthitect", "Andrew");
       positions.put("senior", "John");
       System.out.println(positions);
   }
}

// вывод в консоль
// {junior=Ivan, middle=Roman, senior=John, team lead=Anton, arthitect=Andrew}
Les clés sont toujours uniques, donc un seul senior est enregistré.

LinkedHashMap :

  • maintient l'ordre d'insertion ;
  • plus lent que HashMap ;
  • l'itération devrait être plus rapide que dans HashMap.
Exemple:
public class CollectionExample {

   public static void main(String[] args) {
       LinkedHashMap<String, String> positions = new LinkedHashMap<>();
       positions.put("junior", "Ivan");
       positions.put("middle", "Roman");
       positions.put("senior", "Vasily");
       positions.put("team lead", "Anton");
       positions.put("arthitect", "Andrew");
       positions.put("senior", "John");
       System.out.println(positions);
   }
}

// вывод в консоль
// {junior=Ivan, middle=Roman, senior=John, team lead=Anton, arthitect=Andrew}

Carte arborescente :

Une implémentation de carte qui conserve les entrées triées selon l'ordre naturel de leurs clés, ou mieux encore, en utilisant un comparateur s'il en est fourni dans le constructeur lors de la création de la carte. Exemple:
  1. Sans comparateur

    public class CollectionExample {
    
       public static void main(String[] args) {
           TreeMap<Integer, String> positions = new TreeMap<>();
           positions.put(1, "Ivan");
           positions.put(3, "Roman");
           positions.put(2, "Vasily");
           positions.put(10, "Anton");
           positions.put(7, "Andrew");
           positions.put(1, "John");
           System.out.println(positions);
       }
    }
    
    // вывод в консоль
    // {1=John, 2=Vasily, 3=Roman, 7=Andrew, 10=Anton}
  2. Avec comparateur

    public class CollectionExample {
    
       public static void main(String[] args) {
           //используем реализацию Strategy Pattern'a и добавим компаратор:
           TreeMap<Integer, String> positions = new TreeMap<>(Comparator.reverseOrder());
           positions.put(1, "Ivan");
           positions.put(3, "Roman");
           positions.put(2, "Vasily");
           positions.put(10, "Anton");
           positions.put(7, "Andrew");
           positions.put(1, "John");
           System.out.println(positions);
       }
    }
    
    // вывод в консоль
    // {10=Anton, 7=Andrew, 3=Roman, 2=Vasily, 1=John}
On voit que le tri par ordre croissant est implémenté en standard, mais cela peut être modifié en ajoutant un comparateur au constructeur. TreeMap est bien décrit ici .

30. Parlez-nous de la collection Set et de ses implémentations ?

L'ensemble est un ensemble d'éléments uniques, et c'est sa principale caractéristique. Autrement dit, Set ne permet pas de répéter les mêmes éléments. Il est important ici que les objets ajoutés aient une méthode implémentée equals .

Ensemble de hachage :

  • pas triés ni commandés. Sous le capot se trouve un HashMap avec un espace réservé pour la valeur. Voir par vous-même ;)
  • utilise hashCode pour ajouter des objets ;
  • Il doit être utilisé lorsque vous avez besoin d’objets uniques et que leur ordre n’a pas d’importance.
Exemple:
public class CollectionExample {

   public static void main(String[] args) {
       HashSet<String> positions = new HashSet<>();
       positions.add("junior");
       positions.add("junior");
       positions.add("middle");
       positions.add("senior");
       positions.add("team lead");
       positions.add("architect");
       System.out.println(positions);
   }
}

// вывод в консоль
// [senior, middle, team lead, architect, junior]
Ici, vous pouvez voir que l'élément « junior », qui a été ajouté deux fois, n'est présent que dans une seule instance. Et l'ordre n'est pas le même que lors de l'ajout.

LinkedHashSet :

  • version commandée de HashSet ;
  • prend en charge la liste doublement chaînée pour tous les éléments ;
  • Utilisez-le lorsque vous avez besoin d'ordre dans votre itération.
Exemple:
public class CollectionExample {

   public static void main(String[] args) {
       LinkedHashSet<String> positions = new LinkedHashSet<>();
       positions.add("junior");
       positions.add("junior");
       positions.add("middle");
       positions.add("senior");
       positions.add("team lead");
       positions.add("architect");
       System.out.println(positions);
   }
}

// вывод в консоль
// [senior, middle, team lead, architect, junior]

Ensemble d'arbres :

  • une des deux collections triées ;
  • utilise une structure arborescente rouge-noir et garantit que les éléments sont par ordre croissant ;
  • Sous le capot, c'est un TreeMap avec un talon sur les valeurs. Et les éléments du TreeSet sont les clés du TreeMap (voir aussi ;)).
Exemple:
public class CollectionExample {

   public static void main(String[] args) {
       TreeSet<String> positions = new TreeSet<>();
       positions.add("junior");
       positions.add("junior");
       positions.add("middle");
       positions.add("senior");
       positions.add("team lead");
       positions.add("architect");
       System.out.println(positions);
   }
}

// вывод в консоль
// [architect, junior, middle, senior, team lead]

Des exceptions

31. Qu'est-ce qu'une exception ?

L'exception est un problème qui peut survenir au moment de l'exécution. Il s’agit d’une situation exceptionnelle qui se produit pour une raison quelconque. Le diagramme d'héritage des exceptions ressemble à ceci (vous devez le connaître par cœur ;)) : Top 50 des questions et réponses d'entretien avec Java Core.  Partie 2 - 3Le diagramme montre qu'en général, toutes les exceptions sont divisées en deux groupes : les exceptions et les erreurs. Erreur - Les JVM sont utilisées pour afficher les erreurs après lesquelles l'application n'a plus de sens. Par exemple, StackOverFlowError, qui indique que la pile est pleine et que le programme ne peut plus s'exécuter. Exception : exceptions générées par programme dans le code. Il existe différentes exceptions, cochées et décochées, mais l'essentiel est qu'elles existent, qu'elles puissent être interceptées et que l'application continue de fonctionner. Les exceptions, à leur tour, sont divisées en celles qui héritent de RuntimeException et d'autres descendants d'Exception. Il y a suffisamment d'informations sur cette question. Nous parlerons ci-dessous des exceptions cochées/non cochées.

32. Comment la JVM gère-t-elle les exceptions ?

Comment ça fonctionne? Dès qu'une exception est levée quelque part, le runtime crée un objet d'exception (noté ExcObj). Il stocke toutes les informations nécessaires au travail - l'exception elle-même qui a été levée et l'endroit où elle s'est produite. La création ExcObjet la transmission au runtime ne sont rien d’autre que « lancer une exception ». ExcObjcontient des méthodes qui peuvent être utilisées pour accéder à l'endroit où l'exception a été levée. Cet ensemble de méthodes est appelé Call Stack. Ensuite, le système d'exécution recherche une méthode dans la pile d'appels capable de gérer notre exception. S'il trouve un gestionnaire correspondant, c'est-à-dire que le type d'exception correspond au type du gestionnaire, tout va bien. S'il ne le trouve pas, le runtime transmet tout au gestionnaire d'exceptions par défaut, qui prépare une réponse et se termine. Voici à quoi cela ressemble :
/**
* Пример, в котором показываются две опции — когда находится обработчик для исключения и когда нет.
*/
class ThrowerExceptionExample {

   public static void main(String[] args) throws IllegalAccessException {

       ThrowerExceptionExample example = new ThrowerExceptionExample();

       System.out.println(example.populateString());
   }

   /**
    * Здесь происходит перехват одного из возможных исключений — {@link IOException}.
    * А вот второй будет пробрасываться дальше вверх по вызову.
    */
   private String populateString() throws IllegalAccessException {
       try {
           return randomThrower();
       } catch (IOException e) {
           return "Caught IOException";
       }
   }

   /**
    * Здесь две опции: or бросается {@link IOException} or {@link IllegalAccessException}.
    * Выбирается случайным образом.
    */
   private String randomThrower() throws IOException, IllegalAccessException {
       if (new Random().nextBoolean()) {
           throw new IOException();
       } else {
           throw new IllegalAccessException();
       }
   }
}
Dans notre cas, CallStack ressemblera schématiquement à :

randomThrower() => populateString() => main(String[] args)
Il existe deux options : l'une ou l'autre exception sera levée de manière aléatoire. Pour IOException tout va bien, si elle est générée, alors le résultat du travail sera : "Caught IOException". Mais s'il existe une deuxième exception pour laquelle il n'y a pas de gestionnaire, le programme s'arrêtera avec le résultat suivant :

Exception in thread "main" java.lang.IllegalAccessException
  at ThrowerExceptionExample.randomThrower(CollectionExample.java:38)
  at ThrowerExceptionExample.populateString(CollectionExample.java:24)
  at ThrowerExceptionExample.main(CollectionExample.java:15)

33. Comment les programmeurs gèrent-ils les exceptions ?

Dans les questions ci-dessus, nous avons déjà utilisé certains mots-clés pour travailler avec des exceptions, nous devons maintenant en parler plus en détail. Quels sont les mots-clés ?
  • essayer
  • attraper
  • lancer
  • jette
  • enfin
Il est important de noter que catch, throw et throws ne peuvent être utilisés qu'avec java.lang.Throwable. Cela ne fonctionnera pas avec d'autres types. Nous allons maintenant discuter d'essayer, d'attraper et enfin.
  • try-catch-finallyest une construction qui vous permet d'intercepter et de gérer correctement une exception.
  • try- il ne peut y avoir qu'une seule fois, c'est là que se déroule la logique ;
  • catch— un bloc qui reçoit un certain type d'exception ; il peut y en avoir plusieurs. Par exemple, un bloc try lancera plusieurs exceptions qui n'ont rien à voir les unes avec les autres ;
  • finally- "enfin" ce bloc. Il s'agit d'un bloc qui sera exécuté dans tous les cas, peu importe ce qui est fait dans try, catch.
Voici à quoi cela ressemble :
try {
   // сюда передают тот code, который может вызвать исключение.
} catch (IOException e) {
   // первый catch блок, который принимает IOException и все его подтипы(потомки).
   // Например, нет file при чтении, выпадает FileNotFoundException, и мы уже соответствующе
   // обрабатываем это.
} catch (IllegalAccessException e) {
   // если нужно, можно добавить больше одного catch блока, в этом нет проблем.
} catch (OneException | TwoException e) {
   // можно даже объединять несколько в один блок
} catch (Throwable t) {
   // а можно сказать, что мы принимаем ВСЁ))))
} finally {
   // этот блок может быть, а может и не быть.
   // и он точно выполнится.
}
Lisez attentivement la description de l'exemple et tout sera clair)

34. lancer et lancer en Java

lancer

throwutilisé lorsque vous devez créer explicitement une nouvelle exception. Il est utilisé pour créer et lancer des exceptions personnalisées. Par exemple, les exceptions liées à la validation. Habituellement, pour validation, ils héritent de RuntimeException. Exemple:
// пример пробрасывания исключения
throw new RuntimeException("because I can :D");
Il est important que cette construction ne puisse être utilisée que par quelque chose qui en hérite Throwable. Autrement dit, vous ne pouvez pas dire ceci :
throw new String("How тебе такое, Илон Маск?");
Ensuite, le travail du thread est terminé et la recherche commence pour un gestionnaire capable de le traiter. Lorsqu'il ne le trouve pas, il accède à la méthode qui l'a appelé, et ainsi la recherche remontera la ligne d'appels jusqu'à ce qu'il trouve le gestionnaire correspondant ou quitte l'application en cours d'exécution. Regardons:
// Пример, который демонстрирует работу throw
class ThrowExample {

   void willThrow() throws IOException {
       throw new IOException("Because I Can!");
   }

   void doSomething() {
       System.out.println("Doing something");
       try {
           willThrow();
       } catch (IOException e) {
           System.out.println("IOException was successfully handled.");
       }
   }

   public static void main(String args[]) {
       ThrowExample throwExample = new ThrowExample();
       throwExample.doSomething();
   }
}
Si nous exécutons le programme, nous obtenons le résultat suivant :

Doing something
IOException was successfully handled.

jette

throws— un mécanisme par lequel une méthode peut lever une ou plusieurs exceptions. Ils sont ajoutés séparés par des virgules. Voyons à quel point c'est facile et simple :
private Object willThrow() throws RuntimeException, IOException, FileNotFoundException
De plus, il est important de noter qu’il peut y avoir des exceptions cochées et non cochées. Bien entendu, les exceptions non contrôlées ne peuvent pas être ajoutées à throws, mais les bonnes manières disent le contraire. S'il s'agit de éléments vérifiables, alors en utilisant la méthode qui les génère, vous devez les traiter d'une manière ou d'une autre. Il existe deux options :
  1. Écrivez try-catchavec l'exception d'héritage appropriée et ci-dessus.
  2. Utilisez-le throwsexactement de la même manière pour que quelqu'un d'autre ait déjà ce problème :D

35. Exceptions cochées et non cochées en Java

Il existe deux types d'exceptions en Java : cochées et non cochées.

Exceptions vérifiées :

Ce sont des exceptions qui sont vérifiées au moment de la compilation. Si du code dans une méthode lève une exception vérifiée lors d'une exception, la méthode doit soit la traiter à l'aide de try-catch, soit la transmettre davantage. Par exemple, qui lit une image à partir du chemin "/users/romankh3/image.png", la met à jour d'une manière ou d'une autre (pour nous, ce n'est pas important) et le sauvegarde.
class CheckedImageExample {
   public static void main(String[] args) {
       File imageFile = new File("/users/romankh3/image.png");
       BufferedImage image = ImageIO.read(imageFile);
       updateAndSaveImage(image, imageFile);
   }

   private static void updateAndSaveImage(BufferedImage image, File imageFile) {
       ImageIO.write(image, "png", imageFile);
   }
}
Un tel code ne sera pas compilé, car les méthodes statiques ImageIO.read()lèvent ImageIO.write()une IOException, qui est vérifiée et doit être traitée en conséquence. Il existe ici deux options dont nous avons déjà parlé ci-dessus : soit utiliser try-catch, soit avancer plus loin. Pour une meilleure assimilation, nous ferons ceci et cela. Autrement dit, updateAndSavenous allons simplement le transmettre dans la méthode, puis l'utiliser dans la méthode maintry-catch :
class CheckedImageExample {
   public static void main(String[] args) {
       File imageFile = new File("/users/romankh3/image.png");
       try {
           BufferedImage image = ImageIO.read(imageFile);
           updateAndSaveImage(image, imageFile);
       } catch (IOException e) {
           e.printStackTrace();
       }
   }

   private static void updateAndSaveImage(BufferedImage image, File imageFile) throws IOException {
       ImageIO.write(image, "png", imageFile);
   }
}

Exceptions non vérifiées :

Ce sont les exceptions qui ne sont pas vérifiées au stade de la compilation. Autrement dit, une méthode peut générer une RuntimeException, mais le compilateur ne vous rappellera pas de la gérer d'une manière ou d'une autre. Comme indiqué ci-dessous, tout ce qui hérite de RuntimeException et Error n'est pas coché. Top 50 des questions et réponses d'entretien avec Java Core.  Partie 2 - 4Considérez le programme Java suivant. Le code se compile correctement, mais lève une exception lors de son exécution ArrayIndexOutOfBoundsException. Le compilateur lui permet de compiler car ArrayIndexOutOfBoundsExceptionil s'agit d'une exception non vérifiée. Une situation courante avec un tableau, qui pourrait être :
class CheckedImageExample {
   public static void main(String[] args) {
       int[] array = new int[3];
       array[5] = 12;
   }
}
Le résultat sera :
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
  at main(CheckedImageExample.java:12)
Au fait, avez-vous déjà remarqué qu'en Java personne ne donne de noms courts ? Le plus gros le meilleur. Lui, Spring Framework, a eu beaucoup de succès dans ce domaine : il suffit de prendre une classe BeanFactoryPostProcessor )))

36. Que sont les ressources d'essai ?

Il s'agit d'un mécanisme par lequel toutes les ressources doivent être fermées correctement. Ce n'est pas clair, n'est-ce pas ?) Tout d'abord, qu'est-ce qu'une ressource... Une ressource est un objet, après avoir travaillé avec lequel vous devez le fermer, c'est-à-dire appeler le close(). Une ressource est constituée de tous les objets qui implémentent une interface AutoClosable, qui à son tour implémente une interface Closeable. Il est important pour nous de comprendre que tout InputStreamest OutpuStreamune ressource et doit être libéré correctement et avec succès. C'est exactement pourquoi nous devons utiliser try-with-resourcela structure. Voici à quoi cela ressemble :
private void unzipFile(File zipFile) throws IOException {
   try(ZipInputStream zipOutputStream = new ZipInputStream(new FileInputStream(zipFile))) {
       ZipEntry zipEntry = zipOutputStream.getNextEntry();
       while (zipEntry != null) {

       }
   }
}

private void saveZipEntry(ZipEntry zipEntry) {
   // логика сохранения
}
Dans cet exemple, la ressource est ZipInputStream, après avoir travaillé avec laquelle vous devrez la fermer. Et pour ne pas penser à appeler la méthode close(), nous définissons simplement cette variable dans un bloc try, comme le montre l'exemple, et dans ce bloc nous faisons tout le nécessaire. A quoi sert l'exemple ? Il décompressera l'archive zip. Pour ce faire, vous devez utiliser InputStream'om. Vous pouvez définir plusieurs variables ; elles sont séparées par un point-virgule. Quel est le problème? Mais vous pouvez utiliser finallyun bloc, pourriez-vous dire. Voici un article qui détaille les problèmes liés à cette approche. Il décrit également la liste complète des échecs qui peuvent arriver à quelqu'un qui néglige d'utiliser cette conception. Je recommande de le lire ;) Dans la dernière partie il y a des questions/réponses sur le thème du Multithreading. Mon profil GitHub
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION