JavaRush /Java Blog /Random-IT /Le 50 migliori domande e risposte per l'intervista su Jav...
Roman Beekeeper
Livello 35

Le 50 migliori domande e risposte per l'intervista su Java Core. Parte 2

Pubblicato nel gruppo Random-IT
Le 50 migliori domande e risposte per l'intervista su Java Core. Parte 1 Le 50 migliori domande e risposte per l'intervista su Java Core.  Parte 2 - 1

Collezioni

25. Cosa si intende per Collezioni in Java?

La raccolta è un framework progettato per archiviare e manipolare oggetti. Utilizzato per eseguire le seguenti operazioni:
  • ricerca;
  • ordinamento;
  • manipolazione;
  • aggiunta;
  • cancellazione.
Tutte le classi e le interfacce per il framework Collection sono incluse nel java.utilpacchetto.

26. Quali classi e interfacce sono disponibili nel framework Collection?

Interfacce:
  • Collezione;
  • Elenco;
  • Impostato;
  • Carta geografica;
  • Insieme ordinato;
  • Mappa ordinata;
  • Coda.
Classi:
  • Elenchi:
    1. Lista di array;
    2. Lista collegata;
    3. Vector(deprecato).
  • Imposta:
    1. HashSet;
    2. LinkedHashSet;
    3. Set di alberi.
  • Mappe:
    1. HashMap
    2. Mappa ad albero
    3. HashTable (obsoleto)
    4. LinkedHashMap
  • Coda
    1. Coda prioritaria.

27. Cosa si intende per ordinate e ordinate in collezioni?

Ordinato:

Ciò significa che gli elementi archiviati nella raccolta si basano sui valori aggiunti alla raccolta. In questo modo possiamo scorrere i valori della raccolta in un ordine specifico. In altre parole, ciò significa che gli elementi della collezione hanno un proprio ordine specifico in base al quale sono disposti. Per una migliore comprensione, una raccolta non ordinata memorizza i suoi elementi in ordine casuale. Ad esempio, Sett.

Smistato:

Ciò significa che un gruppo di elementi viene ordinato in una raccolta in base ai dati dell'elemento della raccolta. Cioè, non solo la raccolta è ordinata, ma anche l'ordine degli elementi dipende dai loro valori. Questo ordine potrebbe cambiare se ordini in base a un valore di elemento diverso.

28. Quali raccolte sono disponibili con un'interfaccia Elenco? Come lavori con List?

I valori degli elementi in un foglio si basano sul loro indice: sono ordinati per indice. Sono consentite ripetizioni di elementi (ovvero puoi aggiungere più volte lo stesso oggetto alla raccolta e andrà bene).

Lista di array:

La collezione più comune. Essenzialmente, è un array con una dimensione in espansione dinamica. Il compito di gestire la dimensione dell'array spetta alla raccolta. È importante per noi capire che nella maggior parte dei casi questo è ciò che dobbiamo usare. Peculiarità:
  • ricerca veloce e ricerca rapida nell'indice;
  • la raccolta è ordinata per indice, ma non ordinata;
  • implementa l'interfaccia RandomAccess;
  • aggiungendo lentamente al centro della lista.
Esempio:
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");
   }

}
>> uscita

   [John, John, Roman, Ivan]
L'output mostra che si tratta di elementi ripetibili. Vengono visualizzati nell'ordine in cui sono stati registrati. Cos'altro leggere? Sì, ci sono molte informazioni, non è nemmeno necessario uscire da JavaRush:

Lista collegata:

Questa è una raccolta in cui ogni elemento ha un collegamento agli elementi precedenti e successivi. Questi collegamenti ti consentono di passare da un elemento all'altro. Quando si aggiunge un elemento, i collegamenti agli elementi precedenti e successivi cambiano semplicemente: Le 50 migliori domande e risposte per l'intervista su Java Core.  Parte 2 - 2
  • gli elementi sono collegati tra loro, ovvero viene implementata una lista doppiamente concatenata;
  • la velocità complessiva delle operazioni è notevolmente inferiore rispetto ad ArrayList;
  • una scelta eccellente per un gran numero di inserimenti ed eliminazioni all'interno di un array;
  • implementa le interfacce delle liste Queue e Deque e quindi ha i loro metodi di funzionamento.
Esempio:
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("One");
linkedList.add("Two");
linkedList.add("Three");

29. Ci parli della collezione Map e delle sue implementazioni?

Map è una raccolta di valori-chiave. Esiste una chiave univoca e un valore che corrisponde a quel valore. I metodi vengono utilizzati equals()anche hashcode()per determinare l'unicità di una chiave.

Mappa hash:

  • non smistato o ordinato;
  • utilizzato se l'ordine e l'ordinamento non sono importanti;
  • supporta la chiave nulla.
Esempio:
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}
Le chiavi sono sempre uniche, quindi viene registrato un solo senior.

HashMap collegato:

  • mantiene l'ordine di inserimento;
  • più lento di HashMap;
  • si prevede che l'iterazione sarà più veloce rispetto a HashMap.
Esempio:
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}

Mappa ad albero:

Un'implementazione della mappa che mantiene le voci ordinate in base all'ordine naturale delle relative chiavi o, meglio ancora, utilizzando un comparatore se ne viene fornito uno nel costruttore al momento della creazione della mappa. Esempio:
  1. Senza comparatore

    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. Con comparatore

    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}
Vediamo che l'ordinamento in ordine crescente è implementato come standard, ma questo può essere modificato aggiungendo un comparatore al costruttore. TreeMap è ben descritto qui .

30. Ci parli della collezione Set e delle sue implementazioni?

Il set è un insieme di elementi unici e questa è la sua caratteristica principale. Cioè, Set non consente la ripetizione degli stessi elementi. In questo caso è importante che gli oggetti aggiunti abbiano un metodo implementato equals .

Set hash:

  • non smistato o ordinato. Sotto il cofano c'è una HashMap con un segnaposto per il valore. Guarda tu stesso ;)
  • utilizza hashCode per aggiungere oggetti;
  • Va utilizzato quando è necessario avere oggetti unici e il loro ordine non è importante.
Esempio:
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]
Qui puoi vedere che l'elemento “junior”, che è stato aggiunto due volte, è presente solo in un'unica istanza. E l'ordine non è lo stesso di quando si aggiunge.

LinkedHashSet:

  • versione ordinata di HashSet;
  • supporta elenchi doppiamente collegati per tutti gli elementi;
  • Usalo quando hai bisogno di ordine nella tua iterazione.
Esempio:
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]

Set di alberi:

  • una delle due raccolte ordinate;
  • utilizza una struttura ad albero rosso-nera e garantisce che gli elementi siano in ordine crescente;
  • Sotto il cofano c'è una TreeMap con uno stub sui valori. E gli elementi del TreeSet sono le chiavi della TreeMap (vedi anche ;)).
Esempio:
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]

Eccezioni

31. Cos'è l'eccezione?

L'eccezione è un problema che può verificarsi in fase di esecuzione. Questa è una situazione eccezionale che si verifica per qualche motivo. Il diagramma dell'ereditarietà delle eccezioni è simile al seguente (devi conoscerlo a memoria ;)): Le 50 migliori domande e risposte per l'intervista su Java Core.  Parte 2 - 3Il diagramma mostra che, in generale, tutte le eccezioni sono divise in due gruppi: eccezioni ed errori. Errore : le JVM vengono utilizzate per visualizzare errori dopo i quali l'applicazione non ha più senso. Ad esempio, StackOverFlowError, che indica che lo stack è pieno e il programma non può più essere eseguito. Eccezione : eccezioni generate a livello di codice nel codice. Esistono varie eccezioni, verificate e deselezionate, ma la cosa principale è che esistano e possano essere rilevate e l'applicazione possa continuare a funzionare. Le eccezioni, a loro volta, sono ulteriormente suddivise in quelle che ereditano da RuntimeException e da altri discendenti di Exception. Ci sono abbastanza informazioni su questo problema. Parleremo di quali sono le eccezioni selezionate/deselezionate di seguito.

32. In che modo la JVM gestisce le eccezioni?

Come funziona? Non appena viene lanciata un'eccezione da qualche parte, il runtime crea un oggetto eccezione (indicato come ExcObj). Memorizza tutte le informazioni necessarie per il lavoro: l'eccezione stessa che è stata lanciata e il luogo in cui si è verificata. La creazione ExcObje la trasmissione al runtime non sono altro che "lanciare un'eccezione". ExcObjcontiene metodi che possono essere utilizzati per raggiungere il punto in cui è stata lanciata l'eccezione. Questo insieme di metodi è chiamato Call Stack. Successivamente, il sistema runtime cerca un metodo nello stack di chiamate in grado di gestire la nostra eccezione. Se trova un gestore corrispondente, ovvero il tipo di eccezione corrisponde al tipo nel gestore, va tutto bene. Se non lo trova, il runtime passa tutto al gestore di eccezioni predefinito, che prepara una risposta ed esce. Come appare visivamente:
/**
* Пример, в котором показываются две опции — когда находится обработчик для исключения и когда нет.
*/
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();
       }
   }
}
Nel nostro caso, CallStack apparirà schematicamente come:

randomThrower() => populateString() => main(String[] args)
Ci sono due opzioni: l'una o l'altra eccezione verrà lanciata in modo casuale. Per IOException è tutto ok, se viene generato, il risultato del lavoro sarà: "Caught IOException". Ma se c'è una seconda eccezione per la quale non esiste un gestore, il programma si fermerà con il seguente output:

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. In che modo i programmatori gestiscono le eccezioni?

Nelle domande precedenti, alcune parole chiave sono già state utilizzate per lavorare con le eccezioni; ora dobbiamo parlarne in modo più dettagliato. Quali sono le parole chiave?
  • Tentativo
  • presa
  • gettare
  • lancia
  • Finalmente
È importante notare che prendi, lancia e lancia possono essere utilizzati solo con java.lang.Throwable. Questo non funzionerà con altri tipi. Ora parleremo di provare, catturare e infine.
  • try-catch-finallyè un costrutto che consente di catturare e gestire correttamente un'eccezione.
  • try- può esserci solo una volta, è lì che avviene la logica;
  • catch— un blocco che riceve qualche tipo di eccezione; possono essercene molte. Ad esempio, un blocco try genererà diverse eccezioni che non hanno nulla a che fare tra loro;
  • finally- “finalmente” questo blocco. Questo è un blocco che verrà eseguito in ogni caso, indipendentemente da ciò che viene fatto in try, catch.
Ecco come appare:
try {
   // сюда передают тот code, который может вызвать исключение.
} catch (IOException e) {
   // первый catch блок, который принимает IOException и все его подтипы(потомки).
   // Например, нет file при чтении, выпадает FileNotFoundException, и мы уже соответствующе
   // обрабатываем это.
} catch (IllegalAccessException e) {
   // если нужно, можно добавить больше одного catch блока, в этом нет проблем.
} catch (OneException | TwoException e) {
   // можно даже объединять несколько в один блок
} catch (Throwable t) {
   // а можно сказать, что мы принимаем ВСЁ))))
} finally {
   // этот блок может быть, а может и не быть.
   // и он точно выполнится.
}
Leggi attentamente la descrizione dell'esempio e tutto ti sarà chiaro)

34. lancia e lancia in Java

gettare

throwutilizzato quando è necessario creare esplicitamente una nuova eccezione. Viene utilizzato per creare e generare eccezioni personalizzate. Ad esempio, eccezioni relative alla convalida. Di solito, per la convalida, ereditano da RuntimeException. Esempio:
// пример пробрасывания исключения
throw new RuntimeException("because I can :D");
È importante che questa costruzione possa essere utilizzata solo da qualcosa che eredita da Throwable. Cioè non puoi dire questo:
throw new String("How тебе такое, Илон Маск?");
Successivamente, il lavoro del thread viene terminato e inizia la ricerca di un gestore che possa elaborarlo. Quando non lo trova, va al metodo che lo ha chiamato, quindi la ricerca risalirà lungo la linea delle chiamate finché non troverà il gestore corrispondente o lascerà l'applicazione in esecuzione. Guardiamo:
// Пример, который демонстрирует работу 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();
   }
}
Se eseguiamo il programma, otteniamo il seguente risultato:

Doing something
IOException was successfully handled.

lancia

throws— un meccanismo mediante il quale un metodo può generare una o più eccezioni. Si aggiungono separati da virgole. Vediamo quanto è facile e semplice:
private Object willThrow() throws RuntimeException, IOException, FileNotFoundException
Inoltre, è importante notare che possono esserci eccezioni sia verificate che non verificate. Naturalmente non è possibile aggiungere eccezioni incontrollate throws, ma le buone maniere dicono il contrario. Se questi sono elementi controllabili, utilizzando il metodo che li genera, è necessario elaborarli in qualche modo. Ci sono due opzioni:
  1. Scrivi try-catchcon l'eccezione di ereditarietà appropriata e precedente.
  2. Usalo throwsesattamente nello stesso modo in modo che qualcun altro abbia già questo problema: D

35. Eccezioni selezionate e non selezionate in Java

Esistono due tipi di eccezioni in Java: selezionate e deselezionate.

Eccezioni verificate:

Queste sono eccezioni che vengono controllate in fase di compilazione. Se parte del codice in un metodo lancia un'eccezione controllata durante un'eccezione, il metodo deve elaborarlo utilizzando try-catcho inoltrarlo ulteriormente. Ad esempio, chi legge un'immagine dal percorso "/users/romankh3/image.png", la aggiorna in qualche modo (per noi questo non è importante) e lo salva.
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);
   }
}
Tale codice non verrà compilato, poiché i metodi statici ImageIO.read()lanciano ImageIO.write()una IOException, che viene controllata e deve essere gestita di conseguenza. Ci sono due opzioni qui di cui abbiamo già discusso in precedenza: utilizzare try-catcho inoltrare ulteriormente. Per una migliore assimilazione, faremo questo e quello. Cioè, updateAndSavelo inoltreremo semplicemente nel metodo e quindi lo utilizzeremo nel metodo main try-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);
   }
}

Eccezioni non controllate:

Queste sono le eccezioni che non vengono controllate in fase di compilazione. Cioè, un metodo può generare una RuntimeException, ma il compilatore non ti ricorderà di gestirla in qualche modo. Come mostrato di seguito, tutto ciò che eredita da RuntimeException e Error sono deselezionati. Le 50 migliori domande e risposte per l'intervista su Java Core.  Parte 2 - 4Consideriamo il seguente programma Java. Il codice viene compilato correttamente, ma genera un'eccezione quando viene eseguito ArrayIndexOutOfBoundsException. Il compilatore gli consente di compilare perché ArrayIndexOutOfBoundsExceptionè un'eccezione non controllata. Una situazione comune con un array, che potrebbe essere:
class CheckedImageExample {
   public static void main(String[] args) {
       int[] array = new int[3];
       array[5] = 12;
   }
}
Il risultato sarà:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
  at main(CheckedImageExample.java:12)
A proposito, hai già notato che in Java nessuno dà nomi brevi? Piu 'grande e', meglio 'e. Lui, Spring Framework, ci è riuscito molto bene: basta prendere qualche classe BeanFactoryPostProcessor )))

36. Cosa sono i try-with-resources?

Questo è un meccanismo mediante il quale tutte le risorse devono essere chiuse correttamente. In qualche modo non è chiaro, vero?) Prima di tutto, cos'è una risorsa... Una risorsa è un oggetto, dopo aver lavorato con il quale è necessario chiuderlo, cioè chiamare il file close(). Una risorsa è costituita da tutti gli oggetti che implementano un'interfaccia AutoClosable, la quale a sua volta implementa un'interfaccia Closeable. È importante per noi capire che tutto InputStreamè OutpuStreamuna risorsa e deve essere rilasciato correttamente e con successo. Questo è esattamente il motivo per cui dobbiamo utilizzare try-with-resourcela struttura. Ecco come appare:
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) {
   // логика сохранения
}
In questo esempio la risorsa è ZipInputStream, dopo averla utilizzata sarà necessario chiuderla. E per non pensare a chiamare il metodo close(), definiamo semplicemente questa variabile in un blocco try, come mostrato nell'esempio, e all'interno di questo blocco facciamo tutto il necessario. Cosa fa l'esempio? Decomprimerà l'archivio zip. Per fare ciò è necessario utilizzare InputStream'om. È possibile definire più di una variabile; esse sono separate da un punto e virgola. Qual è il problema? Ma puoi usare finallyun blocco, potresti dire. Ecco un articolo che descrive in dettaglio i problemi con questo approccio. Descrive anche l'intero elenco di guasti che possono verificarsi a chi trascura di utilizzare questo progetto. Ne consiglio la lettura ;) Nella parte finale ci sono domande/risposte sul tema del Multithreading. Il mio profilo GitHub
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION