IT박스

catch가 실제로 아무것도 잡지 못하는 경우

itboxs 2021. 1. 9. 09:38
반응형

catch가 실제로 아무것도 잡지 못하는 경우


이 질문에 이미 답변이 있습니다.

최근에 데이터베이스에 잘못된 데이터가 저장되어 프로그램 충돌이 발생했습니다. 나는 이것을 막을 수있는 방법이 있다고 생각했기 때문에 이것은 나를 혼란스럽게했다.

다음 코드의 목적은 직원 배지 번호를 비교하고 정렬하는 것입니다. 오류가 있으면 -1을 반환하고 soldier on을 반환합니다. 수천 개의 배지 번호 중 하나가 잘못 되었기 때문에 멈추지 마십시오.

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;
}

잘못된 배지 번호 (이 경우 t)가 나오면 "java.lang.IllegalArgumentException : 비교 메서드가 일반 계약을 위반합니다!"라는 메시지가 표시됩니다. catch에서 -1을 반환하는 대신 오류가 발생합니다.

여기서 캐치에 대해 이해하지 못하는 것은 무엇입니까?

전체 스택 추적 :

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)

호출 코드 :

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

예외는 (그것이 무엇이든) 되었다 에 의해 붙 잡았다 catch (Exception e). 이 예외를 기록하지 않았으므로 그것이 무엇인지 알 수 없습니다. 실제로 무슨 일이 일어 났는지 알 수 있도록 어떻게 든 기록해야합니다.

반환 할 때 문제가 발생합니다 -1. 이는 Java의 현재 정렬 알고리즘이 때때로 포착하는 일관성없는 순서의 가능성을 허용합니다. 요컨대, -1오류를 반환 한다는 것은 예외가 두 경우 모두에서 잡히기 때문에 a < bb < a모두 참 이라고 주장한다는 것을 의미합니다 . 이것은 논리적으로 잘못되었습니다. 정렬 알고리즘은이를 감지하고 IllegalArgumentException. compare메서드는 스택 추적에 없습니다 . 에 대한 호출 Collections.sort입니다.

예외를 로깅하는 것 외에도 프로그램의 비교 단계에 도달하기 전에 예외를 처리하십시오. 문자열을 정수로 구문 분석해야하는 경우 Employee개체를 만들 때이를 수행 하여 프로그램의 정렬 단계에 도달하기 전에 유효성 검사가 수행되도록합니다. A Comparator는 데이터의 유효성을 검사 할 필요가 없습니다. 데이터 만 비교해야합니다.


설명

java.lang.IllegalArgumentException : 비교 메소드 가 일반 계약을 위반 합니다 !

예외는 try. 그것이 잡히지 않는 이유입니다. 예외는 클래스 를 사용하는 NotifierHTML.java:363호출 Collection#sort하는 코드에서 발생합니다 TimSort. 예외가 다음에서 슬로우 TimSort.java:868바이 TimSort#mergeHi방법.

Comparator#compare메서드 구현 이 잘못 되었음을 알려줍니다 . 문서에 설명 된대로 계약을 위반합니다 .

순서에 대한 두 인수를 비교합니다. 리턴 네가티브의 정수이고, 제로 또는 양의 첫 번째 인수로서 정수이다 미만 , 거나 보다 큰 제.

구현 자는 sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) 모든 xy. (이것은 x.compareTo(y)예외가 발생하면 예외를 발생시켜야 함을 의미 합니다 y.compareTo(x).)

구현할 경우 도 확인해야 관계가 있음을 이행 : (x.compareTo(y) > 0 && y.compareTo(z) > 0)의미한다 x.compareTo(z) > 0.

마지막으로, 구현 확인해야x.compareTo(y) == 0것을 의미 sgn(x.compareTo(z)) == sgn(y.compareTo(z))모든, z.

구현이 이러한 요구 사항 중 하나를 위반하고 방법이이를 감지했습니다.


문제의 원인

문제는 -1오류가 발생 하면 반환한다는 것 입니다. 두 개의 값 firstsecond. 그리고 그들 중 적어도 하나는 예외를 유발할 것입니다.

따라서 first비교 second하려면 다음을 얻습니다 -1.

compare(first, second) -> -1

어떤 수단 first이다 작은 것보다 second. 그러나 다른 방식으로 비교하면 다음과 같은 결과가 나타납니다 -1.

compare(second, first) -> -1

두 변형 모두에서 예외가 발생하기 때문에 return -1;. 그러나 이것은 귀하의 compare방법이 다음과 같이 말합니다.

first < second
second < first

Both at the same time, which is logically incorrect and violates the contract.


Solution

You need to correctly define where in your ordering unparsable content is placed at. For example let us define that it is always smaller than any number. So we want

text < number

What do we do if both are unparsable? We could say they are equal, we could compare them lexicographical. Let's keep it simple and say that any two texts are considered equal:

text = text

We implement this by checking which of the arguments are unparseable and then returning the correct value:

@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);
}

As hinted in the comments you could replace your whole custom Comparator class by the following statement which generates the same Comparator:

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

Together with a tryParseInteger method like this:

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

While this is not the case, remember that you can throw and catch Throwable instances, and apart from Exceptions there are Errors. Catching them is possible, though when they occur its unlikely that any further work can be done.

So your try-catch would not have caught an Error or any Throwable other than Exception.

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");
    }
}

Which will result in:

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

That exception is not thrown in compare method you pasted here. Check the stacktrace. There is no compare call in it.


The exception is thrown from TimSort.mergeHi() invoked internally as you explicitly invoked Collections.sort() :

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

You could move the catch statement around sort() but as a consequence the sort will not be performed or be no complete. So it seems not to be a good idea.
Long story short : don't violate the compareTo() contract and you would not need to catch any exception that will not happen any longer.

ReferenceURL : https://stackoverflow.com/questions/50378884/when-catch-doesnt-actually-catch-anything

반응형