JavaRush /Blog Java /Random-ES /Análisis de preguntas y respuestas de entrevistas para de...

Análisis de preguntas y respuestas de entrevistas para desarrollador Java. parte 16

Publicado en el grupo Random-ES
¡Hola, amigo! ¿Cuánto tiempo lleva convertirse en desarrollador? Le pregunté a muchas personas diferentes y escuché muchas respuestas diferentes. Para algunas personas incluso un mes puede ser suficiente, pero para otras ni siquiera un año será suficiente. Pero estoy seguro de que convertirse en desarrollador de Java es un camino largo y espinoso, independientemente de sus habilidades iniciales. Después de todo, lo importante no es tanto la habilidad como la terquedad y el trabajo duro. Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 1Por lo tanto, hoy continuamos analizando deliberadamente las preguntas de entrevista más populares para desarrolladores de Java. Estudiarlos te acercará gradualmente a tu preciado objetivo. ¡Empecemos!

17. Dé ejemplos de uso exitoso y fallido de Opcional.

Supongamos que tenemos una determinada serie de valores a través de los cuales pasamos por la secuencia, y al final obtenemos algún Opcional como resultado:

Optional<String> stringOptional = Stream.of("a", "ab", "abc", "abcd")
   .filter(str -> str.length() >= 3)
   .findAny();
Nosotros, como era de esperar, necesitamos obtener el valor de este Opcional . Simplemente usar get() es una mala manera:

String result = stringOptional.get();
¿Pero se supone que este método obtiene el valor de Opcional y nos lo devuelve? Esto es cierto, por supuesto, pero si tiene significado. Bueno, si los valores en el flujo fueran diferentes, y al final recibimos un Opcional vacío , cuando intentemos tomarle un valor usando el método get() , se arrojará lo siguiente: Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 2Lo cual no es bueno. En este caso, es mejor utilizar las siguientes construcciones:
  1. 
    String result = null;
    if (stringOptional.isPresent()) {
     stringOptional.get();
    }

    En este caso, estamos verificando si el elemento está en Opcional . De lo contrario, la cadena resultante tiene su valor anterior.

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

    En este caso, especificamos algún valor predeterminado, que se le dará a la cadena resultante en el caso de un Opcional vacío .

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

    En este caso, nosotros mismos lanzamos una excepción cuando Opcional está vacío .

Esto puede resultar conveniente en una aplicación cuando, por ejemplo, se utiliza el método Spring JPA: findById() , que devuelve valores opcionales . En este caso, con este método intentamos tomar el valor y, si no está allí, lanzamos alguna excepción de tiempo de ejecución , que se procesa a nivel de controlador usando ExceptionHandler y se convierte en una respuesta HTTP con el estado 404 - NOT FOUND . Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 3

18. ¿Es posible declarar un método principal como final?

Sí, claro, nada nos impide declarar el método main() como final . El compilador no producirá errores. Pero vale la pena recordar que cualquier método después de declararlo como final se convertirá en el último método , no anulado. Aunque ¿quién redefinirá main ? Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 4

19. ¿Es posible importar el mismo paquete/clase dos veces? ¿Cuáles podrían ser las consecuencias?

Sí tu puedes. ¿Consecuencias? Tendremos un par de importaciones innecesarias que Intelijj IDEA mostrará en gris, es decir. no usado. Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 5Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 6

20. ¿Qué es el casting? ¿Cuándo podemos obtener una ClassCastException?

La conversión, o conversión de tipos , es el proceso de convertir un tipo de datos en otro tipo de datos: manualmente (conversión implícita) o automáticamente (conversión de tipos explícita). Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 7La conversión automática la realiza el compilador y la conversión manual la realiza el desarrollador. La conversión de tipos para primitivas y clases es algo diferente, por lo que las consideraremos por separado. Tipos primitivos Un ejemplo de conversión automática de tipos primitivos:

int value = 17;
double convertedValue = value;
Como puede ver, aquí no se necesitan manipulaciones adicionales además del signo = . Ejemplo de conversión manual de tipos primitivos:

double value = 17.89;
int convertedValue = (int)value;
En este caso, podemos observar una conversión manual, que se implementa usando (int) , mediante la cual la parte después de la coma se descartará y el valor convertido tendrá un valor de -17. Lea más sobre la conversión de tipos primitivos en este artículo . Bueno, pasemos ahora a los objetos. Tipos de referencia Para los tipos de referencia, la conversión automática es posible para clases descendientes a clases principales. Esto también se llama polimorfismo . Digamos que tenemos una clase Lion que hereda de una clase Cat . En este caso, la conversión automática quedará así:

Cat cat = new Lion();
Pero con un elenco explícito todo es algo más complicado, porque no existe ninguna funcionalidad para cortar el exceso, como ocurre con las primitivas. Y simplemente haciendo una conversión explícita del formulario:

Lion lion= (Lion)new Cat();
Recibirá un error: Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 8de hecho, puede agregar métodos a la clase descendiente de Lion que no estaban originalmente en la clase Cat y luego intentar llamarlos, porque su tipo de objeto se convertirá en Lion . Bueno, no hay lógica en esto. Por lo tanto, la reducción de tipos solo es posible cuando el objeto original era de tipo León pero luego se convirtió a una clase principal:

Lion lion = new Lion();
Cat cat = lion;
Lion newLion = (Lion)cat;
Además, para mayor confiabilidad, se recomienda una conversión restringida para objetos usando la construcción instanciaOf :

if (cat instanceof Lion) {
 newLion = (Lion)new Cat();
}
Lea más sobre las conversiones de tipos de referencia en este artículo .

21. ¿Por qué los marcos modernos utilizan principalmente excepciones no controladas?

Creo que todo esto se debe a que el manejo de excepciones marcadas sigue siendo un código espagueti que se repite en todas partes, pero que no es realmente necesario en todos los casos. Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 9En tales casos, es más fácil realizar el procesamiento dentro del marco, para no volver a poner esto sobre los hombros de los desarrolladores. Sí, por supuesto, puede surgir una situación de emergencia, pero estas mismas excepciones no comprobadas se pueden manejar de una manera más conveniente, sin molestarse en procesarlas en try-catch y sin pasarlas por otros métodos. Basta con convertir la excepción en alguna respuesta HTTP enExceptionHandler .

22. ¿Qué es la importación estática?

Cuando se utilizan datos estáticos (métodos, variables), no se puede crear el objeto en sí, sino hacerlo por el nombre de la clase, pero incluso en este caso necesitamos una referencia a la clase. Con él todo es simple: se agrega mediante importación normal. ¿Pero qué pasa si vamos a utilizar un método estático sin escribir el nombre de la clase, como si fuera un método estático de la clase actual? ¡Esto es posible con la importación estática! En este caso, debemos escribir importación estática y un enlace a ese método. Así, por ejemplo, un método estático de la clase Math para calcular el valor del coseno:

import static java.lang.Math.cos;
Como resultado, podemos usar el método sin especificar el nombre de la clase:

double result = cos(60);
También podemos simplemente cargar todos los métodos estáticos de una clase a la vez usando la importación estática:

import static java.lang.Math.*;
Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 10

23. ¿Cuál es la relación entre los métodos hashCode() y equals()?

Según Oracle , la regla es: si dos objetos son iguales (es decir, el método equals() devuelve verdadero ), deben tener el mismo código hash. Al mismo tiempo, no olvide que dos objetos diferentes pueden tener el mismo código hash. Para comprender por qué equals() y hashCode() siempre se anulan en pares, considere los siguientes casos:
  1. Ambos métodos se anulan.

    En este caso, dos objetos diferentes con los mismos estados internos devolverán equals() - true , mientras que hashCode() devolverán el mismo número.

    Resulta que todo está bien, porque se sigue la regla.

  2. Ambos métodos no se anulan.

    En este caso, dos objetos diferentes con los mismos estados internos devolverán false cuando sea igual() , ya que la comparación es por referencia a través del operador == .

    El método hashCode() también devolverá valores diferentes (lo más probable) ya que produce el valor convertido de la dirección de ubicación de la memoria. Pero para el mismo objeto este valor será el mismo, al igual que equals() en este caso devolverá verdadero solo cuando las referencias apunten al mismo objeto.

    Resulta que en este caso todo está bien y se cumple la regla.

  3. Iguales() anulados , hashCode() no anulados .

    En este caso, para dos objetos diferentes con los mismos estados internos, equals() devolverá true y hashCode() devolverá (muy probablemente) valores diferentes.

    Esto es una violación de la regla, por lo que no se recomienda hacerlo.

  4. equals() no se anula , hashCode() se anula .

    En este caso, para dos objetos diferentes con los mismos estados internos, equals() devolverá falso y hashCode() devolverá los mismos valores.

    Hay una violación de la regla, por lo que el enfoque es incorrecto.

Como puede ver, la regla solo se puede ejecutar cuando se anulan equals() y hashCode() o ambos no se anulan en absoluto. Lea Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 11más sobre equals() y hashCode() en este artículo .

24. ¿Cuándo se utilizan las clases BufferedInputStream y BufferedOutputStream?

InputStream se usa para leer datos byte a byte de algún recurso y OutputStream se usa para escribir datos byte a byte. Pero las operaciones byte a byte pueden ser muy inconvenientes y requerir procesamiento adicional (para poder leer/escribir textos normalmente). En realidad, para simplificar dichos registros de bytes, se introdujo BufferedOutputStream y se introdujo BufferedInputStream para lectura . Estas clases no son más que buffers que acumulan datos, lo que le permite trabajar con datos no byte por byte, sino por paquetes de datos completos (matrices). Cuando se crea, BufferedInputStream toma en su constructor una instancia del tipo InputStream , desde la cual se leen los datos:

BufferedInputStream bufferedInputStream = new BufferedInputStream(System.in);
byte[] arr = new byte[100];
bufferedInputStream.read(arr);
System.in es un objeto InputStream que lee datos de la consola. Es decir, usando este objeto BufferedInputStream , podemos leer datos de InputStream escribiéndolos en la matriz pasada. Esto resulta ser una especie de contenedor de la clase InputStream . La matriz arr de este ejemplo es la matriz que recibe datos de BufferedInputStream . Esto, a su vez, lee datos del InputStream con otra matriz, que por defecto tiene un tamaño de 2048 bytes. Lo mismo ocurre con BufferedOutputStream : se debe pasar una instancia del tipo OutputStream al constructor , en la que escribiremos datos en matrices completas:

byte[] arr = "Hello world!!!".getBytes();
BufferedOutputStream bufferedInputStream = new BufferedOutputStream(System.out);
bufferedInputStream.write(arr);
bufferedInputStream.flush();
System.out es un objeto OutputStream que escribe datos en la consola. El método flush() envía datos desde BufferedOutputStream a OutputStream , vaciando BufferedOutputStream en el proceso . Sin este método, no se registrará nada. Y similar al ejemplo anterior: arr es la matriz desde la cual se escriben los datos en BufferedOutputStream . Desde allí se escriben en OutputStream en una matriz diferente, que por defecto tiene un tamaño de 512 bytes. Lea más sobre estas dos clases en el artículo .

25. ¿Cuál es la diferencia entre las clases java.util.Collection y java.util.Collections?

La colección es una interfaz que encabeza la jerarquía de la colección. Introduce clases que le permiten crear, contener y modificar grupos completos de objetos. Se proporcionan muchos métodos para esto, como add() , remove() , contains() y otros. Interfaces principales de la clase Colección :
  • Set es una interfaz que describe un conjunto que contiene elementos únicos (no repetidos) desordenados.

  • Lista es una interfaz que describe una estructura de datos que almacena una secuencia ordenada de objetos. Estos objetos reciben su propio índice (número), mediante el cual puede interactuar con ellos: tomar, eliminar, cambiar, sobrescribir.

  • La cola es una interfaz que describe una estructura de datos con elementos de almacenamiento en forma de cola que sigue la regla FIFO (primero en entrar, primero en salir) .

Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 12Leer más sobre Colección . Colecciones es una clase de utilidad que proporciona muchos métodos de utilidad diferentes. Por ejemplo:
  • addAll(Collection<? super T> collection, T...element) : agrega los elementos pasados ​​de tipo T a la colección .

  • copy(List<? super T> dest, List<? extends T> src) : copia todos los elementos de la lista src a la lista en dest .

  • Lista vacía() : devuelve una lista vacía.

  • max(Collection<? extends T> collection, Comparator<? super T> comp) : devuelve el elemento máximo de una colección determinada según el orden especificado por el comparador especificado.

  • unmodifiableList(List<? extends T> list) : devuelve una representación no modificable de la lista pasada.

Y hay muchos métodos convenientes de este tipo en Colecciones . Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 13Puede encontrar una lista completa de estos métodos en el sitio web de Oracle . No en vano dije que son cómodos. Después de todo, todos son estáticos. Es decir, no es necesario crear un objeto de esta clase cada vez para poder llamar al método necesario en él. Solo necesita ingresar el nombre de la clase, llamar al método deseado y pasar todos los argumentos requeridos. En resumen, Collection es la interfaz raíz del marco de colecciones. Colecciones es una clase auxiliar para un procesamiento más conveniente de objetos que pertenecen a un tipo de la estructura de colecciones. Bueno, eso es todo por hoy. ¡Mis mejores deseos!Análisis de preguntas y respuestas de entrevistas para desarrollador Java.  Parte 16 - 14
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION