tutorial programacion ejemplo java exception try-catch catch-block comparator

java - ejemplo - manual de programacion android pdf



Cuando la captura en realidad no captura nada (5)

Explicación

java.lang.IllegalArgumentException: ¡El método de comparación viola su contrato general!

La excepción no es lanzada desde tu try . Es por eso que no está atrapado. La excepción proviene de NotifierHTML.java:363 en su código en el que llama a Collection#sort que usa una clase TimSort . La excepción es lanzada desde TimSort.java:868 por el método TimSort#mergeHi .

Le indica que su implementación del método de Comparator#compare es incorrecta. Viola el contrato, tal como se explica en su documentation :

Compara sus dos argumentos por orden. Devuelve un entero negativo , cero o un entero positivo ya que el primer argumento es menor que , igual o mayor que el segundo.

El implementador debe asegurarse de que sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) para todas las x y y . (Esto implica que x.compareTo(y) debe lanzar una excepción si y.compareTo(x) lanza una excepción).

El implementador también debe asegurarse de que la relación sea transitiva : (x.compareTo(y) > 0 && y.compareTo(z) > 0) implica x.compareTo(z) > 0 .

Finalmente, el implementador debe asegurarse de que x.compareTo(y) == 0 implica que sgn(x.compareTo(z)) == sgn(y.compareTo(z)) , para todas las z .

Su implementación viola uno de esos requisitos y el método lo detectó.

Fuente del problema.

El problema es que devuelve -1 si se produce un error. Supongamos que tienes dos valores first y second . Y que al menos uno de ellos provocará la excepción.

Entonces, si quieres comparar first con second , obtienes -1 :

compare(first, second) -> -1

Lo que significa que first es más pequeño que el second . Pero si lo comparas de la otra manera, obtienes -1 también:

compare(second, first) -> -1

Debido a que la excepción se produce en ambas variantes, lo que lleva a su return -1; . Pero esto significa que su método de compare dice:

first < second second < first

Ambos al mismo tiempo, lo cual es lógicamente incorrecto y viola el contrato.

Solución

Debe definir correctamente dónde se ubica en su pedido el contenido no analizable. Por ejemplo, definamos que siempre es más pequeño que cualquier número. Por eso queremos

text < number

¿Qué hacemos si ambos son imparables? Podríamos decir que son iguales, podríamos compararlos lexicográficos. Mantengámoslo simple y digamos que dos textos se consideran iguales:

text = text

Implementamos esto verificando cuáles de los argumentos son imposibles de analizar y luego devolvemos el valor correcto:

@Override public int compare(Employee first, Employee second) { Integer firstValue; Integer secondValue; try { firstValue = Integer.parseInt(first.getBadgeNumber()); } catch (NumberFormatException e) { // Could not parse, set null as indicator firstValue = null; } try { secondValue = Integer.parseInt(second.getBadgeNumber()); } catch (NumberFormatException e) { // Could not parse, set null as indicator secondValue = null; } if (firstValue == null && secondValue != null) { // text < number return -1; } if (firstValue != null && secondValue == null) { // number > text return 1; } if (firstValue == null && secondValue == null) { // text = text return 0; } // Both are numbers return Integer.compare(firstValue, secondValue); }

Como se indicó en los comentarios, puede reemplazar toda su clase personalizada de Comparator por la siguiente declaración que genera el mismo Comparator:

Comparator<Employee> comp = Comparator.nullsLast( Comparator.comparing(e -> tryParseInteger(e.getBadgeNumber())));

Junto con un método tryParseInteger como este:

public static Integer tryParseInteger(String text) { try { return Integer.parseInt(text); } catch (NumberFormatException e) { return null; } }

Esta pregunta ya tiene una respuesta aquí:

Tuve un bloqueo del programa debido a la mala información almacenada en una base de datos recientemente. Esto me confundió, porque pensé que tenía una trampa para evitar esto.

La intención del siguiente código es comparar los números de credencial de los empleados y ordenarlos. Si hay un error, devuelva -1 y el soldado está encendido. No se detenga porque uno de los miles de números de distintivos es incorrecto:

public int compare(Employee t, Employee t1) { Integer returnValue = -1; try { Integer tb = Integer.parseInt(t.getBadgeNumber()); Integer t1b = Integer.parseInt(t1.getBadgeNumber()); returnValue = tb.compareTo(t1b); } catch (Exception e) { returnValue = -1;//useless statement, I know. } return returnValue; }

Cuando se produjo el número de placa incorrecta (como t en este caso), obtuve una "java.lang.IllegalArgumentException: ¡El método de comparación viola su contrato general!" Error en lugar de devolver el -1 en la captura.

¿Qué no entiendo de la captura aquí?

El stacktrace completo:

16-May-2018 14:28:53.496 SEVERE [http-nio-8084-exec-601] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [RequestServlet] in context with path [/AppearanceRequest] threw exception java.lang.IllegalArgumentException: Comparison method violates its general contract! at java.util.TimSort.mergeHi(TimSort.java:868) at java.util.TimSort.mergeAt(TimSort.java:485) at java.util.TimSort.mergeForceCollapse(TimSort.java:426) at java.util.TimSort.sort(TimSort.java:223) at java.util.TimSort.sort(TimSort.java:173) at java.util.Arrays.sort(Arrays.java:659) at java.util.Collections.sort(Collections.java:217) at org.bcso.com.appearancerequest.html.NotifierHTML.getHTML(NotifierHTML.java:363) at org.bcso.com.appearancerequest.AppearanceRequestServlet.processRequest(AppearanceRequestServlet.java:96) at org.bcso.com.appearancerequest.AppearanceRequestServlet.doGet(AppearanceRequestServlet.java:565) at javax.servlet.http.HttpServlet.service(HttpServlet.java:618) at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:301) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:74) at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1015) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652) at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1575) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1533) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745)

El código de llamada:

List<Employee> employeeList = DatabaseUtil.getEmployees(); Collections.sort(employeeList, new BadgeComparator());


Esa excepción no se lanza en el método de comparación que pegaste aquí. Comprueba el stacktrace. No hay ninguna llamada de compare en ella.


La excepción (cualquiera que sea) fue capturada por catch (Exception e) . Usted no registró esta excepción, por lo que no sabe lo que era. Deberías registrarlo de alguna manera para que sepas lo que realmente sucedió.

El problema ocurre cuando devuelves -1 . Esto permite la posibilidad de un ordenamiento incoherente, que el algoritmo de clasificación actual de Java a veces detecta. En resumen, devolver -1 en un error significa que está afirmando que tanto a < b como b < a son verdaderas, porque la excepción se detectará en ambos casos. Esto es lógicamente incorrecto. El algoritmo de clasificación lo detecta y lanza la IllegalArgumentException . Tenga en cuenta que el método de compare no está en su seguimiento de pila; Es la llamada a Collections.sort .

Además de registrar la excepción, manéjela antes de llegar al paso de comparación en su programa. Si tiene que analizar la cadena como un entero, hágalo al crear los objetos de Employee , de modo que la validación ocurra antes de que incluso llegue al paso de clasificación en su programa. Un Comparator no debería tener que validar los datos; Solo debe comparar los datos.


La excepción es lanzada desde TimSort.mergeHi() invocado internamente como invocó explícitamente Collections.sort() :

en java.util.TimSort.mergeHi (TimSort.java:868)

Podría mover la instrucción catch alrededor de sort() pero, como consecuencia, la clasificación no se realizará o no estará completa. Así que no parece ser una buena idea.
Larga historia corta: no viole el contrato compareTo() y no tendrá que atrapar ninguna excepción que ya no suceda.


Si bien este no es el caso, recuerde que puede lanzar y capturar instancias de Throwable y, aparte de las excepciones, hay Errors . Captarlos es posible, aunque cuando ocurren es poco probable que se pueda hacer más trabajo.

Por lo tanto, su intento de captura no habría atrapado un error o cualquier otro Throwable que no sea Excepción.

public static void main(String[] args) { try { throw new Error("test exception try-catch"); } catch (Throwable e) { System.out.println("Error caught in throwable catch"); } try { throw new Error("test exception try-catch"); } catch (Exception e) { System.out.println("Error caught in exception catch"); } }

Lo que resultará en:

Error caught in throwable catch Exception in thread "main" java.lang.Error: test exception try-catch at ...