2009-08-06 13 views
8

EDITAR: Me encantaría leer las reacciones al enfoque de AOP de Steve Reed. Comentarios a su respuesta son alentados!Buscando una manera más fácil de escribir declaraciones de impresión de depuración en Java

Soy un novato, y en algún momento me di cuenta de que sería útil conocer el contenido de una variable durante la ejecución del programa. Así que comencé a hacer esto:

EDITAR: solucionado esto. Solía ​​ser: var + ":" + var, que era totalmente erróneo. Tonto tonto.

System.err.println ("var: " + var); 

Más tarde me enteré de que esto era una práctica común. Al menos, cuando un depurador no estaba disponible o no deseado.

Puedo usar un editor de texto básico, y escribiendo el comunicado de impresión cada vez que necesito para depurar una variable es bastante tedioso, así que pensé, ¿por qué no algo como esto:

void dbug (Object obj) 
{ 
    String variableName = obj.somehowGetVariableName(); 
    String variableContents = obj.toString(); 
    System.out.println (variableName +": " + variableContents); 
} 

Pero al parecer conseguir la variable nombre es más fácil decirlo que hacerlo.

java-reflection-how-to-get-the-name-of-a-variable

estoy atascado con:

System.err.println ("var: " + var); 

O hay una versión abreviada popular de esto?

+0

Solo por curiosidad: "Al menos, cuando un depurador no estaba disponible o no deseado". ¿En qué situación sería esto? ¿Y cuál es el motivo? – Juri

+0

no disponible Entiendo, pero no deseado?!? eso es simplemente negarse a aprender cuán poderosa es una herramienta de depuración real frente a las declaraciones de impresión. – basszero

+0

No disponible cuando aún no tienes un IDE, y no deseado cuando no quieres usar un IDE. El consenso parece ser que un IDE es el único camino a seguir. –

Respuesta

6

No trataría de escribir ningún método elegante sobre la impresión de información de depuración. Simplemente quédese con LOG.debug(...) si está usando un registrador o System.err.println(...) de lo contrario.

Es posible que desee utilizar String.format("var=%s val=%s", "VarName", val) en lugar de la concatenación de cadenas.

Asegúrese de anular el método toString en cada una de sus clases para proporcionar información significativa sobre la depuración.

Al final del día, a menudo es más fácil iniciar el depurador y observar lo que sucede en lugar de tener que rastrear un montón de líneas de depuración registradas.

El único momento en que utilizaría el tipo de método de depuración sería si mi aplicación mantuviera todo el estado dentro de un mapa que podría imprimir fácilmente los pares de valores clave (por ejemplo, el mapa de sesión en una aplicación web) .

+0

¡Gracias por eso! Definitivamente estoy de acuerdo en que su enfoque de cadena formateada es mejor que mi concatenación de cadenas. Utilizándolo de ahora en adelante. –

6

Tenga una mirada en Simple Logging Framework, que le permite escribir:

class Example { 
    static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(Example.class); 

    void doSomething(Object obj1, Object obj2) { 
     LOG.debug("This is object 1: {}, and this is object 2: {}", obj1, obj2); 
    } 
} 
+0

@Tim - ¿Imprime de forma reflexiva el contenido del objeto o llama a String() en el objeto? –

+3

Creo que solo hace un toString() así que esto no ofrece mucho más que evitar la concatenación de cadenas. – pjp

+0

@ pjp- si ese es el caso, no creo que sea muy útil en este escenario, ¿o sí? –

2

Algunos pensamientos:

  1. Me gustaría poner en práctica toString() en objetos de interés, y en ese imprimir los miembros de una forma amigable moda (por ejemplo, convertir las marcas de tiempo a un formato legible, etc.). Normalmente me elegir un formato como:

    Object[member1=,member2=...] 
    

    impresión de lo contrario el objeto solo le dará el nombre de clase, más el código hash de identidad, y (como usted ha descubierto) que no es enormemente útil!

    Commons tiene una facilidad de do this automatically. Pero aquí hay un simple toString()tutorial que creo que es más apropiado.

  2. Existen marcos de registro que pueden interesarle en el futuro. p.ej. echa un vistazo a Log4j. Por el momento, sin embargo, no me preocuparía por eso.

+0

Solo me preocupa la implementación de un método toString que enumera todos los miembros de la clase que contiene miembros cargados de forma perezosa, ya que esto los forzará a todos a crearse. (por ejemplo, colecciones de Hibernate). – pjp

+0

@pjp - buen punto digno de mención –

+0

Admito que siempre asumí la existencia de un toString() sensible. También asumí que los primitivos podrían ser parámetros reales donde se esperaba Object. ¡Gracias por los enlaces! Parece que serán útiles. –

2

Personalmente, no sugiero usar declaraciones sysout en ningún lado. Siempre debe usar un depurador (usando algún IDE). No puedo imaginar dónde no se querría esto.

De lo contrario, sugiero marcos de registro como log4j, pero una vez más, esto ya se vuelve más complicado donde volvería a cambiar a un IDE real con depurador.

+0

El registro siempre es útil para los sistemas de producción cuando no siempre se puede iniciar un depurador. No son demasiado complicados de configurar una vez que encuentres un archivo de configuración de Log4J de ejemplo :) – pjp

+0

De hecho ... cambiar a un buen IDE parece ser un buen paso para esta persona. – jsight

+0

Gracias, Juri, y estoy seguro de que tienes razón. Siempre trato de utilizar la herramienta más simple posible, y mis proyectos son pequeños, por lo que no me han obligado a usar un IDE todavía. He probado Eclipse, sin embargo, y es muy fácil ver que las ventajas son muchas. –

4

creo que System.err.format es lo que quiere:

System.err.format("var: %s\n", var); 

es una abreviatura para:

System.err.println(String.format("var: %s", var)); 
+0

Oye, ahora estamos llegando a algún lado. Gracias por este. pjp sugirió usar String.format ("var =% s val =% s", "VarName", val), y efectivamente, el tuyo es más corto. –

0

Puede obtener acceso a los nombres de variables con AOP y en tiempo de compilación tejer. Lo bueno de esto es que si no haces el tejido, no agregas el código de registro de depuración y, como resultado, tu código de tiempo de ejecución es más rápido y más ágil.

Aquí hay un ejemplo del uso de AspectJ para lanzar una excepción cuando un campo está configurado como nulo. Tenga en cuenta el uso de "joinPoint.getSignature()" para obtener acceso a los metadatos del código.

@Aspect 
public class NotNullValidator { 

    @Pointcut(value = "set(@com.acme.NotNull * *.*) && args(valueBeingSet)") 
    private void setOfNonNullField(final Object valueBeingSet) { } 

    @Before(value = "setOfNonNullField(valueBeingSet)") 
    public void validate(final JoinPoint joinPoint, final Object valueBeingSet) { 
     if (valueBeingSet == null) { 
     throw new NullPointerException("Cannot set " + joinPoint.getSignature().getName() + " to null."); 
     } 
    } 
} 

Ver JoinPoint Javadoc para ver qué más se puede obtener (números de línea, fuente y objetos de destino, etc.).

+0

Esto se ve bastante interesante, ¡pero está por encima de mi nivel de aficionado, eso es seguro! Me tomará un tiempo descubrir cómo probarlo. Tal vez alguien podría comentar sobre este enfoque ... ¿cualquier tomador? –

+0

Definitivamente lleva un tiempo concentrarse en el AOP en general, pero he podido aprovechar el enfoque anterior bastante bien. El aspecto anterior me permite anotar simplemente campos con un @NotNull y CUALQUIER tiempo en que se establezcan, el código de comprobación nula se "entrelazará" durante la compilación. Es realmente agradable y bastante ahorrador de tiempo. –

0

Es un tramo, pero ...

Usted está recibiendo consejos de usar un IDE en lugar de un simple editor de texto. Yo estaría de acuerdo con eso, 100%.

Está recibiendo consejos para utilizar un marco de registro o un depurador en lugar de llamar a println(). Bueno, claro, pero ...

Mejor aún son las pruebas unitarias. No pregunte qué es, cuéntele lo que espera. Entonces, el marco integrado de pruebas unitarias (junit, por lo general) verificará que está obteniendo lo que esperaba. Cuanto más uso las pruebas unitarias, menos necesito depuración y menos necesito println. Y cuando algo cambia, el marco de prueba me dice: no necesito volver a evaluar manualmente la salida de cada prueba, solo mire la barra.

Las pruebas de unidad son mejores que la depuración, mejor que el registro. No son un reemplazo del 100% para la depuración y el registro, pero comienza a usarlos y encontrarás mucha menos necesidad de esas tediosas actividades.

+0

Creo que eres perfecto aquí. Cuando hice un tutorial de Eclipse, todo se trataba de escribir las pruebas primero, y luego básicamente dejar que el IDE creara los métodos a partir de ellas. Siempre he tratado de usar las herramientas más livianas posibles y me he quedado con el editor de texto, a pesar del tedio que induce. Puedo estar en el punto donde esta ideología es contraproducente. Gracias por la visión. –

0

Le recomendaría que configure y use Apache Log4J correctamente. Las líneas System.out o System.err causan una gran cantidad de retraso en la ejecución del programa. (Puede confirmar esto agregando alguna información de tiempo sobre cuánto tiempo tarda su programa sin System.out, etc. y cuánto sin estas líneas.)

Las API de registro utilizan hilos separados para registrar su información de registro en archivos de registro, por eso son más útiles en aplicaciones realistas. Además, las API de registro como Log4J dan mucho control sobre cómo configurar y dar formato a tus registros.Por ejemplo, mire aquí algunos registros generados desde Log4J:

2012-01-05 15:16:41,730 [main] 16 DEBUG dmfssecbuild.IOUtil - 
2012-01-05 15:16:41,730 [main] 16 DEBUG dmfssecbuild.IOUtil - Application Configs Loaded 
2012-01-05 15:16:41,730 [main] 16 DEBUG dmfssecbuild.Constants - Running Application between dates. 
2012-01-05 15:16:41,730 [main] 16 DEBUG dmfssecbuild.Constants - Sat Jan 01 00:00:00 GMT+05:00 2011 From Date 
2012-01-05 15:16:41,730 [main] 16 DEBUG dmfssecbuild.Constants - Mon Dec 31 00:00:00 GMT+05:00 2012 To Date 
0

Si utiliza IntelliJ IDEA, puede utilizar la "plantilla vivo" de acceso directo para la impresión a system.out como soutp (and then a TAB) para depurar los parámetros del método, soutv para rastrear el nombre de una variable junto con su valor, etc.

para leer la lista de atajos \ modificarla, vaya a Archivo-> Configuración> Live Plantillas-> salida

1

Mi primer consejo es: se adhieren a paquete java.util.logging. Realmente no hay necesidad de bibliotecas de registro de terceros.

  1. Obtener instancia de java.util.Logger

    Logger logger = Logger.getLogger ("some.package.XyzClassName");

  2. objetos Log (usando marcador de posición {N})

    Logger.log (Level.INFO, "cosas tala {0} y {1}", nuevo Object [] {new String ("Test") , 1222});

En el caso de las clases definidas por el usuario que necesita tener alguna aplicación anulación toString sensible(), ya que este método es llamado cuando la sustitución de marcador de posición en el mensaje {N}.

Cuestiones relacionadas