JavaRush /Blogue Java /Random-PT /As 50 principais perguntas e respostas da entrevista sobr...
Roman Beekeeper
Nível 35

As 50 principais perguntas e respostas da entrevista sobre Java Core. Parte 2

Publicado no grupo Random-PT
As 50 principais perguntas e respostas da entrevista sobre Java Core. Parte 1 As 50 principais perguntas e respostas da entrevista sobre Java Core.  Parte 2 - 1

Coleções

25. O que significa coleções em Java?

Coleção é uma estrutura projetada para armazenar e manipular objetos. Usado para realizar as seguintes operações:
  • procurar;
  • Ordenação;
  • manipulação;
  • Adição;
  • eliminação.
Todas as classes e interfaces da estrutura Collection estão no java.utilpacote.

26. Quais classes e interfaces estão disponíveis na estrutura Collection?

Interfaces:
  • Coleção;
  • Lista;
  • Definir;
  • Mapa;
  • Conjunto ordenado;
  • Mapa ordenado;
  • Fila.
Aulas:
  • Listas:
    1. ListaArray;
    2. LinkedList;
    3. Vetor (obsoleto).
  • Conjuntos:
    1. HashSet;
    2. LinkedHashSet;
    3. Conjunto de árvores.
  • Mapas:
    1. HashMap
    2. ÁrvoreMapa
    3. HashTable (obsoleto)
    4. LinkedHashMap
  • Fila
    1. Fila de prioridade.

27. O que significa classificado e ordenado em coleções?

Encomendado:

Isso significa que os itens armazenados na coleção são baseados nos valores adicionados à coleção. Dessa forma podemos iterar pelos valores da coleção em uma ordem específica. Em outras palavras, isso significa que os elementos da coleção têm uma ordem específica de acordo com a qual são organizados. Para melhor compreensão, uma coleção não ordenada armazena seus elementos em ordem aleatória. Por exemplo, Definir.

Ordenado:

Isto significa que um grupo de elementos é classificado em uma coleção com base nos dados do elemento da coleção. Ou seja, não só a coleção é ordenada, mas também a ordem dos elementos depende dos seus valores. Esta ordem pode mudar se você classificar por um valor de elemento diferente.

28. Quais coleções existem com uma interface List? Como você trabalha com Lista?

Os valores dos elementos em uma planilha são baseados em seu índice – eles são ordenados por índice. São permitidas repetições de elementos (ou seja, você pode adicionar o mesmo objeto à coleção várias vezes e tudo ficará bem).

Lista de matrizes:

A coleção mais comum. Essencialmente, é um array com tamanho que se expande dinamicamente. A tarefa de gerenciar o tamanho do array cabe à coleção. É importante entendermos que na maioria dos casos é isso que precisamos usar. Peculiaridades:
  • pesquisa rápida e pesquisa rápida de índice;
  • a coleção é ordenada por índice, mas não ordenada;
  • implementa a interface RandomAccess;
  • adicionando lentamente ao meio da lista.
Exemplo:
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");
   }

}
>> saída

   [John, John, Roman, Ivan]
A saída mostra que estes são elementos repetíveis. Eles são exibidos na ordem em que foram gravados. O que mais ler? Sim, são muitas informações, você nem precisa sair do JavaRush:

Lista vinculada:

Esta é uma coleção em que cada elemento possui um link para os elementos anteriores e seguintes. Esses links permitem que você passe de um elemento para outro. Ao adicionar um elemento, os links para os elementos anteriores e seguintes simplesmente mudam: As 50 principais perguntas e respostas da entrevista sobre Java Core.  Parte 2 - 2
  • os elementos são interligados, ou seja, é implementada uma lista duplamente vinculada;
  • a velocidade geral de operação é visivelmente menor do que em ArrayList;
  • uma excelente escolha para um grande número de inserções e exclusões no meio de um array;
  • implementa as interfaces de lista Queue e Deque e, portanto, tem seus métodos de trabalho.
Exemplo:
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("One");
linkedList.add("Two");
linkedList.add("Three");

29. Conte-nos sobre a coleção Map e suas implementações?

Mapa é uma coleção de valores-chave. Existe uma chave exclusiva e um valor que corresponde a esse valor. equals()Métodos também são usados hashcode()​​para determinar a exclusividade de uma chave.

HashMap:

  • não classificado ou ordenado;
  • usado se a ordem e a classificação não forem importantes;
  • suporta chave nula.
Exemplo:
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}
As chaves são sempre únicas, portanto apenas um sênior é registrado.

LinkedHashMap:

  • mantém pedido de inserção;
  • mais lento que HashMap;
  • espera-se que a iteração seja mais rápida do que no HashMap.
Exemplo:
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}

ÁrvoreMapa:

Uma implementação de mapa que mantém as entradas classificadas de acordo com a ordem natural de suas chaves, ou melhor ainda, usando um comparador, se houver algum fornecido no construtor quando o mapa é criado. Exemplo:
  1. Sem comparador

    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. Com comparador

    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}
Vemos que a classificação em ordem crescente é implementada como padrão, mas isso pode ser alterado adicionando um comparador ao construtor. TreeMap está bem descrito aqui .

30. Conte-nos sobre a coleção Set e suas implementações?

Conjunto é um conjunto de elementos únicos, sendo esta a sua principal característica. Ou seja, Set não permite que os mesmos elementos sejam repetidos. É importante aqui que os objetos adicionados tenham um método implementado equals .

HashSet:

  • não classificado ou ordenado. Nos bastidores, há um HashMap com um espaço reservado para o valor. Veja por si mesmo ;)
  • usa hashCode para adicionar objetos;
  • Deve ser usado quando você precisa ter objetos únicos e sua ordem não é importante.
Exemplo:
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]
Aqui você pode ver que o elemento “júnior”, que foi adicionado duas vezes, está presente apenas em uma única instância. E a ordem não é a mesma da adição.

LinkedHashSet:

  • versão solicitada do HashSet;
  • suporta lista duplamente vinculada para todos os elementos;
  • use-o quando a ordem for necessária durante a iteração.
Exemplo:
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]

Conjunto de árvores:

  • uma das duas coleções classificadas;
  • usa uma estrutura de árvore rubro-preta e garante que os elementos estejam em ordem crescente;
  • Nos bastidores, há um TreeMap com um esboço nos valores. E os elementos do TreeSet são as chaves do TreeMap (veja também;)).
Exemplo:
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]

Exceções

31. O que é exceção?

Exceção é um problema que pode ocorrer em tempo de execução. Esta é uma situação excepcional que surge por algum motivo. O diagrama de herança de exceções se parece com este (você precisa saber de cor ;)): As 50 principais perguntas e respostas da entrevista sobre Java Core.  Parte 2 - 3O diagrama mostra que, em geral, todas as exceções são divididas em dois grupos - exceções e erros. Erro - JVMs são usadas para exibir erros após os quais o aplicativo não faz mais sentido. Por exemplo, StackOverFlowError, que indica que a pilha está cheia e o programa não pode mais ser executado. Exceção - exceções geradas programaticamente no código. Existem várias exceções, marcadas e desmarcadas, mas o principal é que elas existem, podem ser detectadas e a aplicação pode continuar funcionando. As exceções, por sua vez, são divididas ainda naquelas que herdam de RuntimeException e demais descendentes de Exception. Há informações suficientes sobre este assunto. Falaremos sobre quais são as exceções marcadas/desmarcadas abaixo.

32. Como a JVM trata exceções?

Como funciona? Assim que uma exceção é lançada em algum lugar, o tempo de execução cria um Objeto de Exceção (denotado como ExcObj). Ele armazena todas as informações necessárias para o trabalho - a própria exceção que foi lançada e o local onde aconteceu. A criação ExcObje a transmissão para o tempo de execução nada mais são do que “lançar uma exceção”. ExcObjcontém métodos que podem ser usados ​​para chegar ao local onde a exceção foi lançada. Este conjunto de métodos é denominado Call Stack. A seguir, o sistema de tempo de execução procura um método na pilha de chamadas que possa lidar com nossa exceção. Se encontrar o manipulador apropriado, ou seja, o tipo de exceção corresponde ao tipo no manipulador, está tudo bem. Se não encontrar, o tempo de execução passa tudo para o manipulador de exceções padrão, que prepara uma resposta e sai. Isto é o que parece:
/**
* Пример, в котором показываются две опции — когда находится обработчик для исключения и когда нет.
*/
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();
       }
   }
}
No nosso caso, CallStack será esquematicamente parecido com:

randomThrower() => populateString() => main(String[] args)
Existem duas opções: uma ou outra exceção será lançada aleatoriamente. Para IOException está tudo ok, se for gerado então o resultado do trabalho será: "Caught IOException". Mas se houver uma segunda exceção para a qual não há manipulador, o programa irá parar com a seguinte saída:

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. Como os programadores lidam com exceções?

Nas questões acima, algumas palavras-chave já foram utilizadas para trabalhar com exceções, agora precisamos falar mais detalhadamente sobre elas. Quais são as palavras-chave?
  • tentar
  • pegar
  • lançar
  • lança
  • finalmente
É importante observar que catch, throw e throws só podem ser usados ​​com java.lang.Throwable. Isso não funcionará com outros tipos. Agora discutiremos try, catch e finalmente.
  • try-catch-finallyé uma construção que permite capturar e tratar corretamente uma exceção.
  • try- só pode haver um tempo, é aí que a lógica acontece;
  • catch— um bloco que recebe algum tipo de exceção; pode haver muitas delas. Por exemplo, um bloco try lançará diversas exceções que não têm nada a ver umas com as outras;
  • finally- “finalmente” este bloco. Este é um bloco que será executado em qualquer caso, independente do que for feito no try, catch.
Isto é o que parece:
try {
   // сюда передают тот code, который может вызвать исключение.
} catch (IOException e) {
   // первый catch блок, который принимает IOException и все его подтипы(потомки).
   // Например, нет file при чтении, выпадает FileNotFoundException, и мы уже соответствующе
   // обрабатываем это.
} catch (IllegalAccessException e) {
   // если нужно, можно добавить больше одного catch блока, в этом нет проблем.
} catch (OneException | TwoException e) {
   // можно даже объединять несколько в один блок
} catch (Throwable t) {
   // а можно сказать, что мы принимаем ВСЁ))))
} finally {
   // этот блок может быть, а может и не быть.
   // и он точно выполнится.
}
Leia atentamente a descrição do exemplo e tudo ficará claro)

34. jogue e jogue em Java

lançar

throwusado quando você precisa criar explicitamente uma nova exceção. É usado para criar e lançar exceções personalizadas. Por exemplo, exceções relacionadas à validação. Geralmente, para validação, eles herdam de RuntimeException. Exemplo:
// пример пробрасывания исключения
throw new RuntimeException("because I can :D");
É importante que esta construção só possa ser utilizada por algo que herde de Throwable. Ou seja, você não pode dizer isso:
throw new String("How тебе такое, Илон Маск?");
Em seguida, o trabalho do thread é encerrado e começa a busca por um manipulador que possa processá-lo. Quando não o encontra, ele vai para o método que o chamou, e assim a busca subirá na linha de chamadas até encontrar o manipulador correspondente ou deixar a aplicação em execução. Vamos olhar:
// Пример, который демонстрирует работу 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 executarmos o programa, obteremos o seguinte resultado:

Doing something
IOException was successfully handled.

lança

throws- um mecanismo pelo qual um método pode lançar uma ou mais exceções. Eles são adicionados separados por vírgulas. Vamos ver como é fácil e simples:
private Object willThrow() throws RuntimeException, IOException, FileNotFoundException
Além disso, é importante notar que pode haver exceções verificadas e não verificadas. É claro que exceções não verificadas não podem ser adicionadas a throws, mas as boas maneiras dizem o contrário. Se forem verificáveis, então, usando o método que os gera, você precisará processá-los de alguma forma. Existem duas opções:
  1. Escreva try-catchcom a exceção de herança apropriada e acima.
  2. Use throwsexatamente da mesma forma para que outra pessoa já tenha esse problema :D

35. Exceções verificadas e não verificadas em Java

Existem dois tipos de exceções em Java – verificadas e desmarcadas.

Exceções verificadas:

Estas são exceções que são verificadas em tempo de compilação. Se algum código em um método lançar uma exceção verificada durante uma exceção,o método deve tratá-lo usando try-catchou encaminhá-lo posteriormente.Por exemplo,que lê uma imagem do caminho "/users/romankh3/image.png",atualiza-a de alguma forma (para nós isso não é importante) e salva de volta.
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);
   }
}
Esse código não será compilado, pois os métodos estáticos ImageIO.read()lançam ImageIO.write()uma IOException, que é verificada e deve ser tratada adequadamente. Existem duas opções aqui que já discutimos acima: usar try-catchou encaminhar ainda mais. Para uma melhor assimilação, faremos isso e aquilo. Ou seja, updateAndSavevamos apenas encaminhá-lo no método e depois usá-lo no método principal 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);
   }
}

Exceções não verificadas:

Estas são as exceções que não são verificadas na fase de compilação. Ou seja, um método pode gerar uma RuntimeException, mas o compilador não irá lembrá-lo de lidar com isso de alguma forma. Conforme mostrado abaixo, temos tudo o que herda de RuntimeException e Error estão desmarcados. As 50 principais perguntas e respostas da entrevista sobre Java Core.  Parte 2 - 4Considere o seguinte programa Java. O código compila bem, mas gera uma exceção quando run ArrayIndexOutOfBoundsException. O compilador permite compilar porque ArrayIndexOutOfBoundsExceptioné uma exceção não verificada. Uma situação comum com um array, que poderia ser:
class CheckedImageExample {
   public static void main(String[] args) {
       int[] array = new int[3];
       array[5] = 12;
   }
}
O resultado será:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
  at main(CheckedImageExample.java:12)
Aliás, você já percebeu que em Java ninguém dá nomes abreviados? Quanto maior melhor. Ele, Spring Framework, teve muito sucesso nisso: basta pegar alguma classe BeanFactoryPostProcessor )))

36. O que são testes com recursos?

Este é um mecanismo pelo qual todos os recursos devem ser fechados corretamente. De alguma forma não está claro, certo?) Primeiro de tudo, o que é um recurso... Um recurso é um objeto, depois de trabalhar com o qual você precisa fechá-lo, ou seja, chamar o close(). Um recurso refere-se a todos os objetos que implementam uma interface AutoClosable, que por sua vez implementa uma interface Closeable. É importante entendermos que tudo InputStreamé OutpuStreamum recurso e precisa ser liberado de forma correta e com sucesso. É exatamente por isso que precisamos usar try-with-resourcea estrutura. Aqui está o que parece:
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) {
   // логика сохранения
}
Neste exemplo, o recurso é ZipInputStream, após trabalhar com o qual será necessário fechá-lo. E para não pensar em chamar o método close(), simplesmente definimos esta variável em um bloco try, como mostra o exemplo, e dentro deste bloco fazemos tudo o que for necessário. O que o exemplo faz? Isso descompactará o arquivo zip. Para fazer isso você precisa usar InputStream'om. Você pode definir mais de uma variável; elas são separadas por ponto e vírgula. Qual é o problema? Mas você pode usar finallyum bloco, você pode dizer. Aqui está um artigo que detalha os problemas dessa abordagem. Ele também descreve toda a lista de falhas que podem ocorrer a alguém que negligencia o uso desse design. Recomendo a leitura ;) Na parte final há perguntas/respostas sobre o tema Multithreading. Meu perfil GitHub
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION