JavaRush /Blog Java /Random-FR /Analyse des questions et réponses des entretiens pour dév...

Analyse des questions et réponses des entretiens pour développeur Java. Partie 16

Publié dans le groupe Random-FR
Bonjour mon ami! Combien de temps faut-il pour devenir développeur ? J'ai interrogé beaucoup de personnes différentes et j'ai entendu beaucoup de réponses différentes. Pour certaines personnes, même un mois peut suffire, mais pour d’autres, même un an ne suffira pas. Mais je sais avec certitude que devenir développeur Java est un chemin épineux et long, quelles que soient vos capacités initiales. Après tout, ce n’est pas tant la capacité qui compte que l’entêtement et le travail acharné. Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 - 1Par conséquent, nous continuons aujourd'hui à analyser délibérément les questions d'entretien les plus populaires pour les développeurs Java. Les étudier vous rapprochera progressivement de votre objectif cher. Commençons!

17. Donnez des exemples d'utilisation réussie et infructueuse de l'option facultative.

Supposons que nous ayons une certaine série de valeurs à travers lesquelles nous parcourons le flux, et qu'à la fin nous obtenions des facultatifs :
Optional<String> stringOptional = Stream.of("a", "ab", "abc", "abcd")
   .filter(str -> str.length() >= 3)
   .findAny();
Comme prévu, nous devons obtenir la valeur de ce Optionnel . Utiliser simplement get() est une mauvaise méthode :
String result = stringOptional.get();
Mais cette méthode est censée récupérer la valeur de Facultatif et nous la renvoyer ? C’est bien sûr vrai, mais si cela a un sens. Eh bien, si les valeurs dans le flux étaient différentes et qu'à la fin nous recevions un Option vide , lorsque nous essayons d'en extraire une valeur à l'aide de la méthode get() , ce qui suit sera renvoyé : Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 - 2Ce qui n'est pas bon. Dans ce cas, il est préférable d'utiliser les constructions suivantes :
  1. String result = null;
    if (stringOptional.isPresent()) {
     stringOptional.get();
    }

    Dans ce cas, nous vérifions si l'élément est en Option . Sinon, la chaîne résultante a son ancienne valeur.

  2. String result = stringOptional.orElse("default value");

    Dans ce cas, nous spécifions une valeur par défaut, qui sera donnée à la chaîne résultante dans le cas d'un Option vide .

  3. String result = stringOptional.orElseThrow(() -> new CustomException());

    Dans ce cas, nous lançons nous-mêmes une exception lorsque Optionnel est vide .

Cela peut être pratique dans une application lorsque, par exemple, la méthode Spring JPA est utilisée - findById() , qui renvoie des valeurs facultatives . Dans ce cas, avec cette méthode, nous essayons de prendre la valeur, et si elle n'est pas là, nous lançons une exception Runtime , qui est traitée au niveau du contrôleur à l'aide de ExceptionHandler et convertie en une réponse HTTP avec le statut 404 - NOT FOUND . Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 - 3

18. Est-il possible de déclarer une méthode principale comme finale ?

Oui, bien sûr, rien ne nous empêche de déclarer la méthode main() comme final . Le compilateur ne produira pas d'erreurs. Mais il convient de rappeler que toute méthode après l'avoir déclarée comme finale deviendra la dernière méthode - non remplacée. Mais qui va redéfinir le principal ??? Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 - 4

19. Est-il possible d’importer deux fois le même package/classe ? Quelles pourraient en être les conséquences ?

Oui, vous pouvez. Conséquences? Nous aurons quelques importations inutiles qu'Intelijj IDEA affichera en gris, c'est-à-dire inutilisé. Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 - 5Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 - 6

20. Qu'est-ce que le casting ? Quand pouvons-nous obtenir une ClassCastException ?

Le cast, ou transtypage de type , est le processus de conversion d'un type de données en un autre type de données : manuellement (casting implicite) ou automatiquement (casting de type explicite). Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 à 7La conversion automatique est effectuée par le compilateur et la conversion manuelle est effectuée par le développeur. La conversion de type pour les primitives et les classes est quelque peu différente, nous les considérerons donc séparément. Types primitifs Un exemple de conversion automatique de types primitifs :
int value = 17;
double convertedValue = value;
Comme vous pouvez le voir, aucune manipulation supplémentaire autre que le signe = n'est nécessaire ici. Exemple de conversion manuelle de types primitifs :
double value = 17.89;
int convertedValue = (int)value;
Dans ce cas, nous pouvons observer une conversion manuelle, qui est implémentée à l'aide de (int) , dans laquelle la partie après la virgule sera supprimée et la valeur convertie aura une valeur de - 17. En savoir plus sur la conversion des types primitifs dans cet article . Eh bien, passons maintenant aux objets. Types référence Pour les types référence, la conversion automatique est possible pour les classes descendantes vers les classes parents. C'est ce qu'on appelle aussi le polymorphisme . Disons que nous avons une classe Lion qui hérite d'une classe Cat . Dans ce cas, la conversion automatique ressemblera à ceci :
Cat cat = new Lion();
Mais avec un casting explicite , tout est un peu plus compliqué, car il n'y a pas de fonctionnalité pour couper les excès, comme avec les primitives. Et il suffit de faire une conversion explicite du formulaire :
Lion lion= (Lion)new Cat();
Vous obtiendrez une erreur : Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 à 8En fait, vous pouvez ajouter des méthodes à la classe descendante Lion qui n'étaient pas à l'origine dans la classe Cat , puis essayer de les appeler, car votre type d'objet deviendra Lion . Eh bien, il n’y a aucune logique là-dedans. Par conséquent, le rétrécissement du type n'est possible que lorsque l'objet d'origine est de type Lion mais a ensuite été converti en classe parent :
Lion lion = new Lion();
Cat cat = lion;
Lion newLion = (Lion)cat;
De plus, pour une plus grande fiabilité, un cast restreint pour les objets est recommandé à l'aide de la construction instanceOf :
if (cat instanceof Lion) {
 newLion = (Lion)new Cat();
}
En savoir plus sur les conversions de type référence dans cet article .

21. Pourquoi les frameworks modernes n'utilisent-ils principalement que des exceptions non contrôlées ?

Je pense que tout cela est dû au fait que la gestion des exceptions vérifiées est toujours du code spaghetti qui est répété partout, mais qui n'est pas vraiment nécessaire dans tous les cas. Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 à 9Dans de tels cas, il est plus facile d'effectuer le traitement à l'intérieur du framework, afin de ne pas le faire reposer une fois de plus sur les épaules des développeurs. Oui, bien sûr, une situation d'urgence peut survenir, mais ces mêmes exceptions non contrôlées peuvent être gérées de manière plus pratique, sans se soucier du traitement en try-catch et sans les transmettre davantage par des méthodes. Il suffit simplement de convertir l'exception en une réponse HTTP dans exceptionHandler .

22. Qu'est-ce que l'importation statique ?

Lorsque vous utilisez des données statiques (méthodes, variables), vous ne pouvez pas créer l'objet lui-même, mais le faire par le nom de la classe, mais même dans ce cas, nous avons besoin d'une référence à la classe. Tout est simple avec : il est ajouté via l'importation régulière. Mais que se passe-t-il si nous utilisons une méthode statique sans écrire le nom de la classe, comme s'il s'agissait d'une méthode statique de la classe actuelle ? C'est possible avec l'importation statique ! Dans ce cas, nous devons écrire une importation statique et un lien vers cette méthode. Comme ceci, par exemple, une méthode statique de la classe Math pour calculer la valeur du cosinus :
import static java.lang.Math.cos;
En conséquence, nous pouvons utiliser la méthode sans spécifier le nom de la classe :
double result = cos(60);
On peut aussi simplement charger toutes les méthodes statiques d’une classe en une seule fois en utilisant static import :
import static java.lang.Math.*;
Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 à 10

23. Quelle est la relation entre les méthodes hashCode() et equals() ?

Selon Oracle , la règle est la suivante : si deux objets sont égaux (c'est-à-dire que la méthode equals() renvoie true ), ils doivent avoir le même code de hachage. Dans le même temps, n'oubliez pas que deux objets différents peuvent avoir le même code de hachage. Pour comprendre pourquoi equals() et hashCode() sont toujours remplacés par paires, considérons les cas suivants :
  1. Les deux méthodes sont remplacées.

    Dans ce cas, deux objets différents avec les mêmes états internes renverront equals() - true , tandis que hashCode() renverra tous deux le même nombre.

    Il s'avère que tout va bien, car la règle est respectée.

  2. Les deux méthodes ne sont pas remplacées.

    Dans ce cas, deux objets différents avec les mêmes états internes renverront false lorsque equals() , puisque la comparaison se fait par référence via l' opérateur == .

    La méthode hashCode() renverra également des valeurs différentes (très probablement) puisqu'elle produit la valeur convertie de l'adresse de l'emplacement mémoire. Mais pour le même objet, cette valeur sera la même, tout comme equals() dans ce cas ne retournera true que lorsque les références pointent vers le même objet.

    Il s’avère que dans ce cas, tout va bien et que la règle est respectée.

  3. Equals() remplacé , pas hashCode() remplacé .

    Dans ce cas, pour deux objets différents avec les mêmes états internes, equals() renverra true et hashCode() renverra (très probablement) des valeurs différentes.

    Il s’agit d’une violation de la règle, il n’est donc pas recommandé de le faire.

  4. equals() n'est pas remplacé , hashCode() est remplacé .

    Dans ce cas, pour deux objets différents avec les mêmes états internes, equals() renverra false et hashCode() renverra les mêmes valeurs.

    Il y a une violation de la règle, donc l’approche est incorrecte.

Comme vous pouvez le voir, la règle ne peut être exécutée que lorsque equals() et hashCode() sont tous deux remplacés ou lorsque les deux ne sont pas remplacés du tout. En savoir Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 à 11plus sur Equals() et hashCode() dans cet article .

24. Quand les classes BufferedInputStream et BufferedOutputStream sont-elles utilisées ?

InputStream est utilisé pour lire les données octet par octet à partir d'une ressource, et OutputStream est utilisé pour écrire des données octet par octet. Mais les opérations octet-octet peuvent être très gênantes et nécessiter un traitement supplémentaire (afin de lire/écrire des textes normalement). En fait, pour simplifier ces enregistrements d'octets, BufferedOutputStream a été introduit et BufferedInputStream a été introduit pour la lecture . Ces classes ne sont rien de plus que des tampons qui accumulent des données, vous permettant de travailler avec des données non pas octet par octet, mais par paquets de données entiers (tableaux). Une fois créé, BufferedInputStream prend dans son constructeur une instance du type InputStream , à partir de laquelle les données sont lues :
BufferedInputStream bufferedInputStream = new BufferedInputStream(System.in);
byte[] arr = new byte[100];
bufferedInputStream.read(arr);
System.in est un objet InputStream qui lit les données de la console. Autrement dit, en utilisant cet objet BufferedInputStream , nous pouvons lire les données du InputStream en les écrivant dans le tableau transmis. Cela s'avère être une sorte de wrapper de la classe InputStream . Le tableau arr de cet exemple est le tableau qui reçoit les données de BufferedInputStream . Celui-ci, à son tour, lit les données de InputStream avec un autre tableau, qui a par défaut une taille de 2048 octets. Il en va de même pour BufferedOutputStream : une instance du type OutputStream doit être passée au constructeur , dans laquelle nous écrirons les données dans des tableaux entiers :
byte[] arr = "Hello world!!!".getBytes();
BufferedOutputStream bufferedInputStream = new BufferedOutputStream(System.out);
bufferedInputStream.write(arr);
bufferedInputStream.flush();
System.out est un objet OutputStream qui écrit des données sur la console. La méthode flush() envoie les données du BufferedOutputStream au OutputStream , vidant le BufferedOutputStream au cours du processus . Sans cette méthode, rien ne sera enregistré. Et similaire à l'exemple précédent : arr est le tableau à partir duquel les données sont écrites dans BufferedOutputStream . À partir de là, ils sont écrits dans OutputStream dans un tableau différent, qui a par défaut une taille de 512 octets. En savoir plus sur ces deux classes dans l'article .

25. Quelle est la différence entre les classes java.util.Collection et java.util.Collections ?

Collection est une interface qui est à la tête de la hiérarchie des collections. Il introduit des classes qui vous permettent de créer, contenir et modifier des groupes entiers d'objets. De nombreuses méthodes sont fournies pour cela, comme add() , remove() , contain() et d'autres. Principales interfaces de la classe Collection :
  • Set est une interface qui décrit un ensemble contenant des éléments uniques (non répétitifs) non ordonnés.

  • List est une interface qui décrit une structure de données qui stocke une séquence ordonnée d'objets. Ces objets reçoivent leur propre index (numéro), à l'aide duquel vous pouvez interagir avec eux : prendre, supprimer, modifier, écraser.

  • La file d'attente est une interface qui décrit une structure de données avec des éléments de stockage sous la forme d'une file d'attente qui suit la règle - FIFO - First In First Out .

Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 à 12En savoir plus sur les collections . Collections est une classe utilitaire qui fournit de nombreuses méthodes utilitaires différentes. Par exemple:
  • addAll(Collection<? super T> collection, T...element) - ajoute les éléments transmis de type T à la collection .

  • copy(List<? super T> dest, List<? extends T> src) - copie tous les éléments de la liste src vers la liste dans dest .

  • emptyList() - renvoie une liste vide.

  • max(Collection<? extends T> collection, Comparator<? super T> comp) - Renvoie l'élément maximum d'une collection donnée selon l'ordre spécifié par le comparateur spécifié.

  • unmodifiableList(List<? extends T> list) - renvoie une représentation non modifiable de la liste transmise.

Et il existe un grand nombre de méthodes pratiques de ce type dans Collections . Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 à 13Une liste complète de ces méthodes est disponible sur le site Web d'Oracle . Ce n’est pas pour rien que j’ai dit qu’ils étaient à l’aise. Après tout, ils sont tous statiques. Autrement dit, vous n'avez pas besoin de créer un objet de cette classe à chaque fois pour y appeler la méthode nécessaire. Il vous suffit de saisir le nom de la classe, d'appeler dessus la méthode souhaitée et de transmettre tous les arguments requis. Pour résumer, Collection est l'interface racine du framework de collections. Collections est une classe d'assistance pour un traitement plus pratique des objets appartenant à un type de la structure des collections. Eh bien, c'est tout pour aujourd'hui. Tous mes vœux!Analyse des questions et réponses des entretiens pour développeur Java.  Partie 16 à 14
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION