JavaRush /Blog Java /Random-PL /50 najpopularniejszych pytań i odpowiedzi do rozmów kwali...
Roman Beekeeper
Poziom 35

50 najpopularniejszych pytań i odpowiedzi do rozmów kwalifikacyjnych dotyczących języka Java Core. Część 2

Opublikowano w grupie Random-PL
50 najpopularniejszych pytań i odpowiedzi do rozmów kwalifikacyjnych dotyczących języka Java Core. Część 1 50 najpopularniejszych pytań i odpowiedzi do rozmów kwalifikacyjnych dotyczących języka Java Core.  Część 2 - 1

Kolekcje

25. Co oznaczają Kolekcje w Javie?

Kolekcja to framework przeznaczony do przechowywania obiektów i manipulowania nimi. Służy do wykonywania następujących operacji:
  • szukaj;
  • sortowanie;
  • manipulacja;
  • dodatek;
  • usunięcie.
Wszystkie klasy i interfejsy frameworka Collection znajdują się w java.utilpakiecie.

26. Jakie klasy i interfejsy są dostępne w frameworku Collection?

Interfejsy:
  • Kolekcja;
  • Lista;
  • Ustawić;
  • Mapa;
  • posortowany zestaw;
  • posortowana mapa;
  • Kolejka.
Zajęcia:
  • Listy:
    1. Lista tablic;
    2. Połączona lista;
    3. Wektor (przestarzałe).
  • Zestawy:
    1. Zestaw skrótów;
    2. Połączony zestaw hash;
    3. Zestaw drzew.
  • Mapy:
    1. HashMapa
    2. Mapa Drzewa
    3. HashTable (przestarzałe)
    4. Połączona mapa Hash
  • Kolejka
    1. Kolejka priorytetowa.

27. Co oznacza posortowane i uporządkowane w zbiorach?

Zamówione:

Oznacza to, że elementy przechowywane w kolekcji opierają się na wartościach dodanych do kolekcji. W ten sposób możemy iterować po wartościach z kolekcji w określonej kolejności. Innymi słowy oznacza to, że elementy kolekcji mają swój określony porządek, według którego są ułożone. Dla lepszego zrozumienia kolekcja, która nie jest uporządkowana, przechowuje swoje elementy w losowej kolejności. Na przykład zestaw.

Posortowane:

Oznacza to, że grupa elementów jest sortowana w kolekcję na podstawie danych elementu kolekcji. Oznacza to, że nie tylko kolekcja jest uporządkowana, ale także kolejność elementów zależy od ich wartości. Kolejność ta może ulec zmianie, jeśli sortujesz według innej wartości elementu.

28. Jakie kolekcje są dostępne z interfejsem List? Jak pracujesz z Listą?

Wartości elementów w arkuszu opierają się na ich indeksie – są uporządkowane według indeksu. Dopuszczalne są powtórzenia elementów (czyli możesz dodać ten sam obiekt do kolekcji kilka razy i będzie ok).

Lista tablic:

Najczęstsza kolekcja. Zasadniczo jest to tablica o dynamicznie rosnącym rozmiarze. Zadanie zarządzania rozmiarem tablicy spoczywa na kolekcji. Ważne jest, abyśmy zrozumieli, że w większości przypadków właśnie tego musimy użyć. Osobliwości:
  • szybkie wyszukiwanie i szybkie wyszukiwanie indeksowe;
  • kolekcja jest uporządkowana według indeksu, ale nie posortowana;
  • implementuje interfejs RandomAccess;
  • powoli dodając do środka listy.
Przykład:
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");
   }

}
>> wyjście

   [John, John, Roman, Ivan]
Z wyniku wynika, że ​​są to elementy powtarzalne. Są one wyświetlane w kolejności, w jakiej zostały zapisane. Co jeszcze przeczytać? Tak, informacji jest mnóstwo, nie trzeba nawet opuszczać JavaRush:

Połączona lista:

Jest to zbiór, w którym każdy element posiada odnośnik do poprzedniego i kolejnego elementu. Linki te umożliwiają przechodzenie z jednego elementu do drugiego. Podczas dodawania elementu linki do poprzednich i kolejnych elementów po prostu się zmieniają: 50 najpopularniejszych pytań i odpowiedzi do rozmów kwalifikacyjnych dotyczących języka Java Core.  Część 2 - 2
  • elementy są ze sobą połączone, to znaczy realizowana jest podwójnie połączona lista;
  • ogólna prędkość działania jest zauważalnie niższa niż w ArrayList;
  • doskonały wybór w przypadku dużej liczby wstawień i usunięć w środku tablicy;
  • implementuje interfejsy list Queue i Deque i dlatego ma swoje metody działania.
Przykład:
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("One");
linkedList.add("Two");
linkedList.add("Three");

29. Opowiedz nam o kolekcji Map i jej implementacjach?

Mapa to zbiór klucz-wartość. Istnieje unikalny klucz i wartość odpowiadająca tej wartości. Metody służą equals()również hashcode()do określenia niepowtarzalności klucza.

Mapa skrótów:

  • nie posortowane ani uporządkowane;
  • używane, jeśli kolejność i sortowanie nie są ważne;
  • obsługuje klucz zerowy.
Przykład:
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}
Klucze są zawsze unikalne, dlatego rejestrowany jest tylko jeden senior.

Połączona mapa Hash:

  • utrzymuje kolejność wstawiania;
  • wolniejszy niż HashMap;
  • oczekuje się, że iteracja będzie szybsza niż w HashMap.
Przykład:
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}

Mapa drzewa:

Implementacja mapy, która utrzymuje wpisy posortowane zgodnie z naturalną kolejnością kluczy lub jeszcze lepiej, przy użyciu komparatora, jeśli jest on dostępny w konstruktorze podczas tworzenia mapy. Przykład:
  1. Bez komparatora

    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. Z komparatorem

    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}
Widzimy, że sortowanie w kolejności rosnącej jest standardowo zaimplementowane, ale można to zmienić, dodając do konstruktora komparator. TreeMap jest dobrze opisany tutaj .

30. Opowiedz nam o kolekcji Set i jej wdrożeniach?

Zestaw to zestaw unikalnych elementów i to jest jego główna cecha. Oznacza to, że Set nie pozwala na powtarzanie tych samych elementów. Ważne jest tutaj, aby dodawane obiekty miały zaimplementowaną metodę equals .

Zestaw skrótów:

  • nie posortowane ani uporządkowane. Pod maską znajduje się HashMap z symbolem zastępczym wartości. Sam zobacz ;)
  • używa hashCode do dodawania obiektów;
  • Należy go stosować, gdy potrzebne są unikalne obiekty, a ich kolejność nie jest istotna.
Przykład:
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]
Tutaj widać, że element „młodszy”, który został dodany dwukrotnie, występuje tylko w jednym przypadku. A kolejność nie jest taka sama jak przy dodawaniu.

Połączony zestaw Hash:

  • zamówiona wersja HashSet;
  • obsługuje podwójnie połączoną listę wszystkich elementów;
  • użyj go, gdy podczas iteracji wymagana jest porządek.
Przykład:
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]

Zestaw drzew:

  • jedna z dwóch posortowanych kolekcji;
  • wykorzystuje czerwono-czarną strukturę drzewa i dba o to, aby elementy były ułożone w kolejności rosnącej;
  • Pod maską znajduje się TreeMap z fragmentem wartości. A elementy TreeSet są kluczami do TreeMap (patrz także ;)).
Przykład:
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]

Wyjątki

31. Co to jest wyjątek?

Wyjątek to problem, który może wystąpić w czasie wykonywania. Jest to sytuacja wyjątkowa , która powstaje z jakiegoś powodu. Diagram dziedziczenia wyjątków wygląda tak (trzeba go znać na pamięć ;)): Z 50 najpopularniejszych pytań i odpowiedzi do rozmów kwalifikacyjnych dotyczących języka Java Core.  Część 2 - 3diagramu wynika, że ​​ogólnie wszystkie wyjątki dzielą się na dwie grupy - wyjątki i błędy. Błąd - maszyny JVM służą do wyświetlania błędów, po których aplikacja nie ma już sensu. Na przykład StackOverFlowError, który mówi, że stos jest pełny i program nie może już działać. Wyjątek — wyjątki generowane programowo w kodzie. Są różne wyjątki, zaznaczone i niesprawdzone, ale najważniejsze, że istnieją, można je wyłapać i aplikacja może dalej działać. Wyjątki z kolei dzielą się na te, które dziedziczą z RuntimeException i innych potomków wyjątku. Jest wystarczająco dużo informacji na ten temat. Poniżej omówimy zaznaczone/niesprawdzone wyjątki.

32. Jak JVM obsługuje wyjątki?

Jak to działa? Gdy tylko gdzieś zostanie zgłoszony wyjątek, środowisko wykonawcze tworzy obiekt wyjątku (oznaczony jako ExcObj). Przechowuje wszystkie informacje niezbędne do pracy - sam wyjątek, który został zgłoszony i miejsce, w którym to nastąpiło. Tworzenie ExcObji przesyłanie do środowiska wykonawczego to nic innego jak „zgłoszenie wyjątku”. ExcObjzawiera metody, za pomocą których można dostać się do miejsca, w którym został zgłoszony wyjątek. Ten zestaw metod nazywa się stosem wywołań. Następnie system wykonawczy szuka metody w stosie wywołań, która może obsłużyć nasz wyjątek. Jeśli znajdzie odpowiednią procedurę obsługi, to znaczy typ wyjątku pasuje do typu w procedurze obsługi, wszystko jest w porządku. Jeśli go nie znajdzie, środowisko wykonawcze przekazuje wszystko do domyślnej procedury obsługi wyjątków, która przygotowuje odpowiedź i kończy działanie. Jak to wygląda wizualnie:
/**
* Пример, в котором показываются две опции — когда находится обработчик для исключения и когда нет.
*/
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";
       }
   }

   /**
    * Здесь две опции: Lub бросается {@link IOException} Lub {@link IllegalAccessException}.
    * Выбирается случайным образом.
    */
   private String randomThrower() throws IOException, IllegalAccessException {
       if (new Random().nextBoolean()) {
           throw new IOException();
       } else {
           throw new IllegalAccessException();
       }
   }
}
W naszym przypadku CallStack będzie schematycznie wyglądać następująco:

randomThrower() => populateString() => main(String[] args)
Istnieją dwie opcje: jeden lub drugi wyjątek zostanie zgłoszony losowo. Dla IOException wszystko jest ok, jeżeli zostanie wygenerowany to efektem pracy będzie: "Caught IOException". Jeśli jednak istnieje drugi wyjątek, dla którego nie ma procedury obsługi, program zatrzyma się i wyświetli następujący wynik:

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. Jak programiści radzą sobie z wyjątkami?

W powyższych pytaniach pewne słowa kluczowe zostały już użyte do pracy z wyjątkami; teraz musimy omówić je bardziej szczegółowo. Jakie są słowa kluczowe?
  • próbować
  • złapać
  • rzucić
  • rzuca
  • Wreszcie
Należy pamiętać, że funkcji catch, rzucania i rzucania można używać wyłącznie z komendą java.lang.Throwable. To nie będzie działać z innymi typami. Teraz omówimy try, catch i wreszcie.
  • try-catch-finallyto konstrukcja, która pozwala poprawnie przechwycić i obsłużyć wyjątek.
  • try- może być tylko jeden raz, wtedy dzieje się logika;
  • catch— blok, który otrzymuje jakiś wyjątek; może być ich wiele. Na przykład blok try zgłosi kilka wyjątków, które nie mają ze sobą nic wspólnego;
  • finally- „wreszcie” ten blok. Jest to blok, który zostanie wykonany w każdym przypadku, niezależnie od tego, co zostanie wykonane podczas try, catch.
Oto jak to wygląda:
try {
   // сюда передают тот kod, который может вызвать исключение.
} catch (IOException e) {
   // первый catch блок, который принимает IOException и все его подтипы(потомки).
   // Например, нет plik при чтении, выпадает FileNotFoundException, и мы уже соответствующе
   // обрабатываем это.
} catch (IllegalAccessException e) {
   // если нужно, можно добавить больше одного catch блока, в этом нет проблем.
} catch (OneException | TwoException e) {
   // можно даже объединять несколько в один блок
} catch (Throwable t) {
   // а можно сказать, что мы принимаем ВСЁ))))
} finally {
   // этот блок может быть, а может и не быть.
   // и он точно выполнится.
}
Przeczytaj uważnie opis przykładu i wszystko będzie jasne)

34. rzucanie i rzucanie w Javie

rzucić

throwużywane, gdy trzeba jawnie utworzyć nowy wyjątek. Służy do tworzenia i zgłaszania niestandardowych wyjątków. Na przykład wyjątki związane z walidacją. Zwykle w celu sprawdzenia poprawności dziedziczą z RuntimeException. Przykład:
// пример пробрасывания исключения
throw new RuntimeException("because I can :D");
Ważne jest, aby z tej konstrukcji mogło korzystać tylko coś, co dziedziczy po Throwable. Oznacza to, że nie można powiedzieć tak:
throw new String("Jak тебе такое, Илон Маск?");
Następnie praca wątku zostaje zakończona i rozpoczyna się poszukiwanie procedury obsługi, która mogłaby go przetworzyć. Jeśli go nie znajdzie, przechodzi do metody, która go wywołała, więc wyszukiwanie będzie kontynuowane w górę linii wywołań, dopóki nie znajdzie odpowiedniego modułu obsługi lub nie pozostawi aplikacji uruchomionej. Spójrzmy:
// Пример, который демонстрирует работу 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();
   }
}
Jeśli uruchomimy program, otrzymamy następujący wynik:

Doing something
IOException was successfully handled.

rzuca

throws- mechanizm, dzięki któremu metoda może zgłosić jeden lub więcej wyjątków. Dodaje się je oddzielając przecinkami. Zobaczmy jakie to łatwe i proste:
private Object willThrow() throws RuntimeException, IOException, FileNotFoundException
Co więcej, ważne jest, aby pamiętać, że mogą istnieć zarówno zaznaczone, jak i niesprawdzone wyjątki. Oczywiście niesprawdzonych wyjątków nie można dodać do throws, ale dobre maniery mówią inaczej. Jeśli są to elementy sprawdzalne, to korzystając z metody, która je generuje, musisz je jakoś przetworzyć. Istnieją dwie opcje:
  1. Zapisz try-catchz odpowiednim i wyższym wyjątkiem dziedziczenia.
  2. Użyj go throwsdokładnie w ten sam sposób, aby ktoś inny miał już ten problem :D

35. Sprawdzone i niesprawdzone wyjątki w Javie

W Javie istnieją dwa typy wyjątków – zaznaczone i niesprawdzone.

Sprawdzone wyjątki:

Są to wyjątki sprawdzane w czasie kompilacji. Jeśli jakiś kod w metodzie zgłosi sprawdzony wyjątek podczas wyjątku, metoda musi albo obsłużyć go za pomocą try-catch, albo przekazać dalej.Na przykład, który odczytuje obraz ze ścieżki „/users/romankh3/image.png”, aktualizuje go w jakiś sposób (dla nas to nie jest ważne) i zapisuje to z powrotem.
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);
   }
}
Taki kod nie zostanie skompilowany, ponieważ metody statyczne ImageIO.read()zgłaszają ImageIO.write()wyjątek IOException, który jest sprawdzany i należy go odpowiednio obsłużyć. Istnieją dwie opcje, które już omówiliśmy powyżej: albo użyj try-catch, albo przekaż dalej. Dla lepszej asymilacji zrobimy to i tamto. Oznacza to, że updateAndSavepo prostu przekażemy go w metodzie, a następnie użyjemy w metodzie głównej 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);
   }
}

Niesprawdzone wyjątki:

Są to wyjątki, które nie są sprawdzane na etapie kompilacji. Oznacza to, że metoda może wygenerować wyjątek RuntimeException, ale kompilator nie przypomni Ci, abyś w jakiś sposób sobie z tym poradził. Jak pokazano poniżej, mamy odznaczone wszystko, co dziedziczy po RuntimeException i Error. 50 najpopularniejszych pytań i odpowiedzi do rozmów kwalifikacyjnych dotyczących języka Java Core.  Część 2 - 4Rozważmy następujący program Java. Kod kompiluje się dobrze, ale po uruchomieniu zgłasza wyjątek ArrayIndexOutOfBoundsException. Kompilator pozwala na kompilację, ponieważ ArrayIndexOutOfBoundsExceptionjest to niesprawdzony wyjątek. Typowa sytuacja z tablicą, która może wyglądać następująco:
class CheckedImageExample {
   public static void main(String[] args) {
       int[] array = new int[3];
       array[5] = 12;
   }
}
Rezultatem będzie:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
  at main(CheckedImageExample.java:12)
Swoją drogą, czy zauważyłeś już, że w Javie nikt nie podaje krótkich nazw? Im większy tym lepszy. On, Spring Framework, odniósł w tym duży sukces: po prostu weź trochę klasy BeanFactoryPostProcessor )))

36. Co to są próby z zasobami?

Jest to mechanizm, dzięki któremu wszystkie zasoby muszą zostać poprawnie zamknięte. To jakoś nie jest jasne, prawda?) Po pierwsze, czym jest zasób... Zasób to obiekt, z którym po pracy trzeba go zamknąć, czyli wywołać close(). Zasób odnosi się do wszystkich obiektów implementujących interfejs AutoClosable, który z kolei implementuje interfejs Closeable. Ważne jest, abyśmy zrozumieli, że wszystko InputStreamjest OutpuStreamzasobem i należy go prawidłowo i skutecznie uwolnić. Właśnie dlatego musimy użyć try-with-resourcetej struktury. Oto jak to wygląda:
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) {
   // логика сохранения
}
W tym przykładzie zasób to ZipInputStream, po pracy z którym będziesz musiał go zamknąć. Aby nie myśleć o wywołaniu metody close(), po prostu definiujemy tę zmienną w bloku try, jak pokazano w przykładzie, i w tym bloku robimy wszystko, co konieczne. Co robi przykład? Rozpakuje archiwum zip. Aby to zrobić, musisz użyć InputStream„om. Można zdefiniować więcej niż jedną zmienną; są one oddzielone średnikiem. Jaki jest problem? Można jednak powiedzieć, że można użyć finallybloku. Oto artykuł szczegółowo opisujący problemy związane z tym podejściem. Opisano w nim także całą listę niepowodzeń, jakie mogą przytrafić się osobie, która zaniedba stosowanie tej konstrukcji. Polecam przeczytać ;) W końcowej części znajdują się pytania/odpowiedzi na temat Wielowątkowości. Mój profil na GitHubie
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION