1

I am trying to sort my user scores. It works well in local but when I looked at server logs it will throws a lot of exceptions. So I tried to null checks and catch exceptions but exception still throws an exception. I am not sure what is the exception.

Collections.sort(userScores, new Comparator<UserScore>() {
            @Override
            public int compare(UserScore o1, UserScore o2) {

                try {
                    if(o1 == null || o1.getScore() == null) {
                        return 1;
                    }
                    if(o2 == null || o2.getScore() == null) {
                        return -1;
                    }
                    if(o1.getScore().doubleValue() > o2.getScore().doubleValue())
                        return -1;
                    return 1;   
                }catch(Exception ex) {
                    logger.severe(ex.getMessage());
                    return 0;
                }

            }
        });

And my code throws,

java.lang.IllegalArgumentException: Comparison method violates its general contract!
        at java.util.TimSort.mergeLo(TimSort.java:777) ~[na:1.8.0_181]
        at java.util.TimSort.mergeAt(TimSort.java:514) ~[na:1.8.0_181]
        at java.util.TimSort.mergeCollapse(TimSort.java:441) ~[na:1.8.0_181]
        at java.util.TimSort.sort(TimSort.java:245) ~[na:1.8.0_181]
        at java.util.Arrays.sort(Arrays.java:1438) ~[na:1.8.0_181]
        at java.util.List.sort(List.java:478) ~[na:1.8.0_181]
        at java.util.Collections.sort(Collections.java:175) ~[na:1.8.0_181]
        at com.tll.treeofwords.game.service.GameService.generateRanking(GameService.java:179) ~[classes!/:0.0.1-SNAPSHOT]
        at com.tll.treeofwords.game.service.GameService.getCurrentGame(GameService.java:76) ~[classes!/:0.0.1-SNAPSHOT]
        at com.tll.treeofwords.game.service.GameService.getCurrentGame(GameService.java:59) ~[classes!/:0.0.1-SNAPSHOT]
        at com.tll.treeofwords.game.service.GameService$$FastClassBySpringCGLIB$$d5f3b9ef.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) ~[spring-tx-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673) ~[spring-aop-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at com.tll.treeofwords.game.service.GameService$$EnhancerBySpringCGLIB$$38f6aa6d.getCurrentGame(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at com.tll.treeofwords.game.controller.GameController.getGame(GameController.java:59) ~[classes!/:0.0.1-SNAPSHOT]
        at com.tll.treeofwords.game.controller.GameController$$FastClassBySpringCGLIB$$b9539785.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:669) ~[spring-aop-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at com.tll.treeofwords.game.controller.GameController$$EnhancerBySpringCGLIB$$388a70ef.getGame(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at sun.reflect.GeneratedMethodAccessor145.invoke(Unknown Source) ~[na:na]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133) ~[spring-web-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97) ~[spring-webmvc-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
Andronicus
  • 25,419
  • 17
  • 47
  • 88
Abdullah Tellioglu
  • 1,434
  • 1
  • 10
  • 26

2 Answers2

3

Your Comparator doesn't properly handle the case of treating two nulls as being equal. If you compare two objects, o1 and o2, which are both null, your code will result in:

compare(o1,o2) == 1

and also:

compare(o2,o1) == 1

That should be impossible, since o1 can't simultaneously be larger and smaller than o2. Thus the error that you're seeing.

You need to modify your code to return 0 if both o1 and o2 (or their respective getScore() methods) are null.

Jordan
  • 2,273
  • 9
  • 16
2

It gives same results no matter what order of parameters passed to the overriden compare method. Suppose we have o1.getScore().doubleValue() == o2.getScore().doubleValue(). Then compare(o1, o2) == 1 && compare(o2, o1) == 1. The contract for compare is that for every pair of arguments o1 and o2, the following must be true: compare(o1, o2) + compare(o2, o1) == 0.

Andronicus
  • 25,419
  • 17
  • 47
  • 88