java - todas - Causa que las excepciones de tiempo de ejecución se ordenen correctamente con println en la salida de la consola
todas las excepciones en java (2)
¿Por qué está sucediendo esto y qué se puede hacer para corregir el problema?
Porque syserr y sysout son flujos de datos separados, pero la consola del sistema (IDE) está intentando mostrar ambos simultáneamente. Esto se puede solucionar usando un Logger
que generalmente ordena correctamente las entradas en el registro.
Otra posibilidad es invocar System.setErr y asignarlo a PrintStream
para un archivo de registro de errores. Esta sería la solución equivalente de Java para redirigir la secuencia de error.
Un problema común con la salida de la consola VM Java es que System.out y System.err generalmente no se sincronizan correctamente, posiblemente porque están en subprocesos diferentes. Esto produce resultados mezclados como los siguientes:
la salida de depuración se mezcló con el seguimiento de la pila de excepción en tiempo de ejecución
[8, 1, 3, 5, 9, 13, 15, 17, 19]
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 9
scanning xAnswer: 1 xValue: 1 total: 1 [1, 1, 0, 0, 0, 0, 0, 0, 0]
at cra.common.Group_jsc.listSubsetSum(Group_jsc.java:29)
scanning xAnswer: 2 xValue: 2 total: 4 [2, 1, 2, 0, 0, 0, 0, 0, 0]
at cra.common.Group_jsc.main(Group_jsc.java:12)
scanning xAnswer: 3 xValue: 3 total: 9 [3, 1, 2, 3, 0, 0, 0, 0, 0]
scanning xAnswer: 4 xValue: 4 total: 18 [4, 1, 2, 3, 4, 0, 0, 0, 0]
scanning xAnswer: 5 xValue: 5 total: 31 [5, 1, 2, 3, 4, 5, 0, 0, 0]
reset to xAnswer: 4 xValue: 5 total: 26 [4, 1, 2, 3, 5, 5, 0, 0, 0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
scanning xAnswer: 5 xValue: 6 total: 41 [5, 1, 2, 3, 5, 6, 0, 0, 0]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
reset to xAnswer: 4 xValue: 6 total: 35 [4, 1, 2, 3, 6, 6, 0, 0, 0]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
scanning xAnswer: 5 xValue: 7 total: 52 [5, 1, 2, 3, 6, 7, 0, 0, 0]
reset to xAnswer: 4 xValue: 7 total: 45 [4, 1, 2, 3, 7, 7, 0, 0, 0]
scanning xAnswer: 5 xValue: 8 total: 64 [5, 1, 2, 3, 7, 8, 0, 0, 0]
reset to xAnswer: 4 xValue: 8 total: 56 [4, 1, 2, 3, 8, 8, 0, 0, 0]
Process finished with exit code 1
Como la excepción se produjo al final del proceso, esperaría que la impresión de la excepción se produjera DESPUÉS de todas las impresiones del programa. ¿Por qué está sucediendo esto y qué se puede hacer para corregir el problema?
(tenga en cuenta que este ejemplo particular es de la consola IDEA de IntelliJ, pero lo mismo ocurre en Eclipse y otros IDE de Java)
Un problema común con la salida de la consola VM Java es que System.out y System.err generalmente no se sincronizan correctamente,
No, están sincronizados perfectamente. El problema es que las líneas están entremezcladas porque se imprimen como llamadas separadas a println(...)
. Este es el código de Exception.printStackTrace()
:
StackTraceElement[] trace = getOurStackTrace();
for (int i=0; i < trace.length; i++)
s.println("/tat " + trace[i]);
Los registradores (como log4j) obtienen el seguimiento completo de la pila y convierten varias líneas en una sola llamada de salida de registro, que luego persiste atómicamente.
¿Por qué está sucediendo esto y qué se puede hacer para corregir el problema?
Por lo general, con los programas de Unix, el estándar de salida se almacena temporalmente mientras que el error estándar no lo es. No pensé que esto fuera cierto con Java, pero quizás sí. Para leer los javadocs de System.out
:
La corriente de salida "estándar". Esta secuencia ya está abierta y lista para aceptar datos de salida. Normalmente, esta secuencia corresponde a la salida de visualización u otro destino de salida especificado por el entorno o usuario del host.
Versus para System.err
:
Por convención, esta secuencia de salida se usa para mostrar mensajes de error u otra información que debería llamar la atención inmediata de un usuario, incluso si el flujo principal de salida, el valor de la variable
out
, se ha redirigido a un archivo u otro destino que sea típicamente no monitoreado continuamente.
Vea esta respuesta para más detalles: ¿Por qué a veces se imprimen las declaraciones System.err?
Si esto se ejecuta desde la línea de comando, debe redirigir la salida y la salida err a diferentes archivos. A continuación, se indica cómo hacerlo usando ~ unix:
Cómo redirigir stderr y stdout a diferentes archivos en la misma línea de bash?
En Java, puede usar System.setOut(...)
y System.setErr(...)
para enviar la salida diferente a diferentes PrintStream
para que las líneas no se entrelacen.
Editó la pregunta para observar que esto está sucediendo desde dentro de un IDE. Si necesita usar System.out
y err
, puede redirigirlos utilizando el código de Java anterior.
Sin embargo, es típico usar código de registro en su lugar. Los paquetes de registro comunes son log4j o logback, que escribe un único mensaje de registro multilínea de forma atómica en el archivo de salida para que no se intercalen. Como @fge menciona, también hay java.util.logging
integrado en la JVM aunque los otros paquetes proporcionan más características.