Ha sido una gran semana. Actualmente estoy revisando el borrador final de mi próximo libro de depuración . Este es siempre un momento aleccionador y emocionante. Un momento en el que de repente todos los meses de trabajo se vuelven "reales".
También grabé 9 videos para YouTube, lo que elevó el total de videos en el curso a 29 (con muchos más en camino). Estoy comenzando dos cursos gratuitos adicionales, uno dirigido a principiantes absolutos .
Otro es sobre la programación Java moderna que lanzaré muy pronto. Ambos serán gratuitos en (obligatorio "me gusta, suscribirse y compartir").
En la publicación de esta semana, hablaremos sobre los puntos de interrupción. Es largo ya que lo que queremos decir cuando decimos punto de interrupción es realmente solo "punto de interrupción de línea". Hay mucho más para ellos, como puede ver a continuación.
Bienvenido de nuevo a la cuarta parte de la depuración en Scale, donde pateamos traseros y tomamos nombres. ¡Nombres de variables!
En esta sección, analizamos los puntos de interrupción, que son las unidades de trabajo más básicas durante la depuración. Pero hay mucho más en ellos que solo romper.
Hablamos sobre el punto de interrupción más básico en nuestra primera entrega. Esta vez, profundizaremos un poco más y analizaremos algunos de los matices menos conocidos.
Comenzamos con puntos de interrupción condicionales. Los puntos de interrupción condicionales nos permiten definir una condición para un golpe de punto de interrupción. Esto evita que el subproceso se detenga constantemente en un punto de interrupción. Discutí esto antes con el objeto marcador myThread que creamos en el video anterior.
En este caso, solo nos detenemos si es diferente del hilo actual. Eso significa que este punto de interrupción solo llegará si un subproceso diferente lo invoca. Es una excelente manera de detectar problemas relacionados con subprocesos, como interbloqueos o carreras. Vale la pena repetir esta característica ya que es una característica muy importante.
Los puntos de interrupción del método son bastante problemáticos.
Como repaso, podemos colocar un punto de interrupción de línea en cualquier línea del método, y el punto de interrupción se detendrá allí. Esto es tan omnipresente que simplemente lo llamamos un "punto de ruptura".
Podemos alternar el punto de interrupción de línea estándar con control-F8 o, alternativamente, en una Mac con Command-F8
.
Los puntos de interrupción del método se detienen cuando ingresamos un método. Podrías pensar que esto es inútil. ¿Por qué no usar un punto de interrupción de línea?
Tendrías razón. Los puntos de interrupción de métodos son mucho más lentos y no debería usarlos: para esto... Sin embargo, hay un caso de uso para los puntos de interrupción de métodos.
Tenga en cuenta que debido a que los puntos de interrupción del método son tan lentos, el IDE suele emularlos. Simplemente usa puntos de interrupción de línea para simular puntos de interrupción de método. Esto es prácticamente transparente para nosotros como usuarios del IDE, pero debemos saberlo porque, en el pasado, este no era el caso.
Todavía puede encontrar mensajes de usuarios en StackOverflow que se quejan de la lentitud de los puntos de interrupción del método.
Para ver el caso de uso de los puntos de interrupción del método, vayamos a la ventana de administración de puntos de interrupción. Digamos que queremos interrumpir todos los métodos que comienzan con las letras I y S en las clases cuyo nombre comienza con Prime.
Podemos hacer esto usando una expresión como esta para detenernos en todos esos métodos basados en un patrón. Esto puede parecer exagerado, pero en realidad es muy útil si tiene una clase base abstracta cuyas subclases siguen una convención de nomenclatura y tienen muchos métodos relacionados.
Desea realizar un seguimiento de todo, y puede hacerlo utilizando este enfoque. Tenga en cuenta que también puede usar puntos de rastreo aquí y obtener un registro muy profundo. Discutiremos los puntos de seguimiento en unos minutos.
Los puntos de vigilancia de campo no son su punto de interrupción típico. Un punto de observación se detendrá cada vez que cambie el valor del campo o cada vez que se lea. Esta es una forma muy interesante de detectar un caso en el que algún código muta una variable o descubre cómo se propaga un valor de campo en el código.
Observe que podemos ajustar si se detiene en operaciones de lectura, operaciones de escritura o ambas usando este cuadro de diálogo. También podemos hacer que el punto de observación sea condicional al igual que con cualquier otro punto de interrupción.
Se llama punto de observación y no punto de interrupción porque no es el punto donde se detiene el código. Se detiene en el punto de acceso, no en el campo mismo.
Los IDE proporcionan una interfaz de usuario de administración para todos los puntos de interrupción. Podemos administrar los puntos de interrupción que ya tenemos y crear nuevos puntos de interrupción en el menú Ver puntos de interrupción. Puedo abrirlo a través de la opción de menú Ver puntos de interrupción, o puedo usar la combinación de teclas Shift-Control-F8
.
Tenga en cuenta que, en una Mac, necesitamos usar el comando en lugar de la tecla de control.
En este cuadro de diálogo, podemos deshabilitar, eliminar y editar puntos de interrupción. Notará que tenemos muchas opciones aquí que discutiremos pronto. Podemos agregar puntos de interrupción desde aquí. Hay varias opciones interesantes, pero ahora solo agregaré un punto de interrupción de campo simple.
Podemos establecer un punto de interrupción para que se detenga cuando se lanza una excepción. Pero es un pequeño problema. tengo dos opciones Primero, puedo detectar una excepción específica por su nombre. Esto es útil si sabe de antemano la excepción que se lanzará.
Pero no puedo pensar en muchos casos en los que esto sucediera, y aún no sabía la línea donde se lanza la excepción.
El caso de uso más valioso es capturar todas las excepciones. La razón por la que esto es útil es que a veces es posible que no mire la consola durante la depuración. Las excepciones pueden registrarse allí y podría perderlas por completo.
Podría reiniciar la sesión de depuración y podría pasar por alto estas excepciones. Pero si un punto de interrupción se detiene repentinamente en una excepción, es difícil pasarlo por alto. ¡El problema es que la captura de todas las excepciones no funciona de manera predeterminada!
Desafortunadamente, esto es difícil de mostrar en una aplicación principal principal simple, así que cambié la demostración a una aplicación simple de arranque de primavera. El contenido de la aplicación no es importante para este caso. Habilitemos la captura de cualquier excepción y veamos qué sucede...
Después de habilitar la captura, trato de continuar, pero al instante llega al punto de interrupción una y otra y otra vez. El código sondea un WebService en segundo plano. A ese servicio web le falta un encabezado HTTP, por lo que el código que analiza ese encabezado falla en una NumberFormatException.
Estamos atascados en el código que arroja esa excepción que es válida ya que Java no proporcionó otra forma de analizar los encabezados numéricos cuando se escribió ese código.
Entonces, ¿qué podemos hacer? Esto hace que detenerse en cualquier excepción sea inútil para casi cualquier aplicación del mundo real.
Movamos la ventana un poco y luego hagamos zoom para ver lo que estamos haciendo aquí.
Ahora podemos definir un filtro de clase. Observe que prefijo ambos filtros con un carácter menos para convertir esto en un filtro de exclusión. Aquí defino un filtro para todos los paquetes Java y todos los paquetes Sun. Eso significa que cada excepción que se maneja dentro de estos paquetes no se romperá.
Una vez que presiono Aceptar, puedo presionar continuar y la aplicación se ejecuta sin interrumpir las excepciones problemáticas. ¡Otras excepciones funcionarán como de costumbre y nos avisarán cuando algo se rompa en nuestro código!
Es sorprendente que este no sea el valor predeterminado de IDE. Sin ella, la característica es prácticamente inútil.
Los Tracepoints o LogPoints son algunos de los tipos de puntos de interrupción más importantes que tenemos. Podemos agregar un punto de seguimiento haciendo shift-clic en el canalón. Esto abre un cuadro de diálogo de punto de interrupción familiar, pero se ve un poco diferente. En primer lugar, observe esto:
La opción de suspensión no está marcada; tenga en cuenta que podemos convertir cualquier punto de interrupción en un punto de seguimiento al desmarcar la casilla de verificación suspender. De forma predeterminada, se rompe un punto de interrupción. Detiene el hilo actual y lo suspende para que podamos inspeccionar tranquilamente la pila de aplicaciones y ver qué está pasando.
Un punto de seguimiento no suspende el subproceso actual. La aplicación llega al punto de interrupción y luego continúa ejecutándose sin detenerse. Esto es bastante innovador, ¿cómo se pasa por alto?
Bueno, no lo haces. En su lugar, podemos hacer varias otras cosas...
Podemos registrar las palabras "golpe de punto de ruptura" siempre que alcancemos el punto de ruptura, pero esto no es tan útil a menos que tengamos solo un punto de rastreo y solo queramos saber si llegamos a ese punto. Podemos imprimir un seguimiento de la pila cada vez que alcancemos el punto de seguimiento, lo que es más útil. Pero no por mucho.
Es difícil leer muchos rastros en una lista y seguirlos. En lo que quiero centrarme es en otra cosa.
Tenga en cuenta que evaluar y registrar ya tenían el valor de cnt
porque tenía el valor de cnt
seleccionado en el IDE antes de hacer clic en el canal.
Podemos escribir cualquier expresión que queramos imprimir aquí. Puedo invocar un método para escribir cadenas descriptivas, etc. Esta es, literalmente, una declaración de registro estándar que puedo agregar dinámicamente al código. Tenga en cuenta que todavía puedo hacer que este punto de rastreo sea condicional como cualquier punto de interrupción condicional.
Eso significa que puedo imprimir cualquier valor en este momento. Como cualquier registrador. Esta es una característica espectacular. Imagine los puntos de interrupción del método que discutimos anteriormente con estos puntos de rastreo; podemos iniciar sesión instantáneamente a escala. Presionamos Aceptar.
Y luego ejecute este programa; ¡podemos ver el registro que agregamos en el punto de seguimiento impreso en la consola como si lo hubiéramos escrito en el código!
La agrupación y la denominación son cruciales una vez que ampliamos nuestra depuración.
Podemos nombrar un punto de ruptura usando la descripción para indicar su significado semántico. Esto es muy útil cuando trabajamos con muchos puntos de interrupción. También podemos agruparlos en base a archivos, paquetes, etc.
Pero lo bueno es que podemos crear grupos personalizados para los puntos de interrupción y deshabilitar los puntos de interrupción en el grupo con una sola palanca. ¡Eso es muy conveniente!
Nos evita tener que pulsar tediosamente continuar cuando intentamos llegar a un estado y nos permite gestionar muchos puntos de interrupción.
Pero el verdadero valor aquí está a escala. Supongamos que tiene una sesión de depuración compleja con varios puntos de seguimiento que se ejecutan simultáneamente.
Puede agrupar la sesión y deshabilitar los puntos de interrupción mientras cambia a una rama diferente para depurar otra cosa. Luego vuelve a donde estabas cuando hayas terminado.
A veces, un punto de interrupción se golpea constantemente y solo necesitamos una pila específica.
Podemos deshabilitar un punto de interrupción hasta que se alcance un punto de interrupción diferente o una excepción, momento en el cual el punto de interrupción se habilitará automáticamente. Esto nos ahorra la necesidad de presionar continuar todo el tiempo si solo queremos probar una ruta específica.
Esto también funciona con excepciones y puntos de interrupción de excepción, y podemos decidir el comportamiento posterior. ¿Queremos volver a desactivarlo o seguir como hasta ahora?
Esto es muy útil para el caso de una falla que solo pasa por un camino específico. Puedo agregar un punto de rastreo al primer método. Luego deshabilite el punto de interrupción real que quiero en ese punto de seguimiento.
Los filtros de instancia solo nos permiten aceptar un punto de interrupción de una instancia de objeto específica.
Observe la instancia del objeto actual marcado como "esto" en el reloj. Observe que tiene el símbolo arroba seguido del número 656.
Este es el ID de objeto Java que es equivalente a un puntero en otros lenguajes de programación. En los filtros de instancia, podemos limitar el punto de interrupción para que solo se alcance para un objeto específico.
Digamos que este punto de interrupción de línea se ve afectado por varias instancias, pero solo me importan los resultados de una instancia de objeto específica y quiero filtrar todo el ruido. Puedo abrir el cuadro de diálogo de detalles avanzados haciendo clic aquí.
Necesito verificar la opción de filtro de instancia y luego escribir el ID de objeto de la instancia que quiero filtrar. Esto significará que el punto de interrupción no se detendrá para otros tipos de instancias. Para aplicar este cambio, presiono listo.
En este punto, podemos ver que el filtro de la instancia aún se detiene en el punto de interrupción esperado...
Entonces, el siguiente paso es cambiar el filtro de instancia a una instancia de objeto diferente. Estoy inventando un número ya que esto es solo para una prueba.
Tenga en cuenta que cuando hago clic con el botón derecho en el punto de interrupción, obtengo una versión personalizada de este cuadro de diálogo porque tenemos un filtro de instancia en su lugar. Esta es una característica realmente interesante que hace que la interfaz de usuario sea mucho más fácil de usar.
Ahora que hemos realizado ese cambio, el punto de interrupción ya no se rompe.
Los filtros de clase no tienen sentido para un punto de interrupción de línea típico. Los filtros de clase tienen sentido cuando se usa un punto de observación de campo o un punto de interrupción de excepción.
En este caso, tengo un campo público. Filtro el acceso al campo para ignorar todo acceso desde la clase principal principal. Si una clase diferente accede al campo, se alcanzará el punto de interrupción.
Esto es muy útil, de lo contrario, podría obtener muchos resultados en el punto de observación de la clase actual. Pero quiero ver otros casos.
El filtro de llamadas implementa un filtro basado en la firma del método de invocación. Para usarlo, nuevamente debemos ir al menú avanzado. Admite comodines, por lo que puedo limitar a la persona que llama para que solo permita el método de ejecución.
Tenga en cuenta que utiliza la notación JVM para la firma del método, que es un tema bastante complejo del que hablaré más adelante. Tengo una sección que cubre eso en mi libro de depuración.
El método sigue deteniéndose en el punto de interrupción como se esperaba porque, como podemos ver aquí, el método de ejecución está en el seguimiento de la pila. Entonces, el filtro se aplica correctamente y llega al punto de interrupción.
Podemos volver a personalizar el punto de interrupción en la interfaz de usuario de edición rápida para el filtro. En este caso, cambié el filtro para buscar un método llamado detener que no existe y, de hecho, el punto de interrupción ya no se rompe.
Este ha sido un video largo, espero que lo hayas encontrado educativo y completo. En el próximo video, hablaremos sobre la depuración de flujos y colecciones.
Si tiene alguna pregunta, utilice la sección de comentarios. ¡Gracias!