2017-01-13 4 views
1

을 위반 : 이것은에 의해 호출왜이 코드 던져 예외를 않습니다 - 비교 방법은 내가 IllegalArgumentException가 던지고 다음과 같은 코드를 사용하고는 일반적으로 계약

java.lang.IllegalArgumentException: Comparison method violates its general contract! 
    at java.util.TimSort.mergeLo(TimSort.java:747) 
    at java.util.TimSort.mergeAt(TimSort.java:483) 
    at java.util.TimSort.mergeCollapse(TimSort.java:410) 
    at java.util.TimSort.sort(TimSort.java:214) 
    at java.util.TimSort.sort(TimSort.java:173) 
    at java.util.Arrays.sort(Arrays.java:659) 
    at java.util.Collections.sort(Collections.java:217) 

:

// Copyright (c) 2003-2014, Jodd Team (jodd.org). All Rights Reserved. 

package jodd.util; 

import java.util.Comparator; 

/** 
* Compares two strings in natural, alphabetical, way. 
*/ 
public class NaturalOrderComparator<T> implements Comparator<T> { 

    protected final boolean ignoreCase; 

    public NaturalOrderComparator() { 
     ignoreCase = false; 
    } 

    public NaturalOrderComparator(boolean ignoreCase) { 
     this.ignoreCase = ignoreCase; 
    } 

    /** 
    * Compare digits at certain position in two strings. 
    * The longest run of digits wins. That aside, the greatest 
    * value wins. 
    */ 
    protected int compareDigits(String str1, int ndx1, String str2, int ndx2) { 
     int bias = 0; 

     while (true) { 
      char char1 = charAt(str1, ndx1); 
      char char2 = charAt(str2, ndx2); 

      boolean isDigitChar1 = CharUtil.isDigit(char1); 
      boolean isDigitChar2 = CharUtil.isDigit(char2); 

      if (!isDigitChar1 && !isDigitChar2) { 
       return bias; 
      } 
      if (!isDigitChar1) { 
       return -1; 
      } 
      if (!isDigitChar2) { 
       return 1; 
      } 

      if (char1 < char2) { 
       if (bias == 0) { 
        bias = -1; 
       } 
      } else if (char1 > char2) { 
       if (bias == 0) { 
        bias = 1; 
       } 
      } else if (char1 == 0 && char2 == 0) { 
       return bias; 
      } 

      ndx1++; 
      ndx2++; 
     } 
    } 

    public int compare(T o1, T o2) { 
     String str1 = o1.toString(); 
     String str2 = o2.toString(); 

     int ndx1 = 0, ndx2 = 0; 
     int zeroCount1, zeroCount2; 
     char char1, char2; 

     int result; 

     while (true) { 
      // only count the number of zeroes leading the last number compared 
      zeroCount1 = zeroCount2 = 0; 

      char1 = charAt(str1, ndx1); 
      char2 = charAt(str2, ndx2); 

      // skip over leading spaces or zeros in both strings 

      while (Character.isSpaceChar(char1) || char1 == '0') { 
       if (char1 == '0') { 
        zeroCount1++; 
       } else { 
        zeroCount1 = 0; // counts only last 0 prefixes, space char interrupts the array of 0s 
       } 
       ndx1++; 
       char1 = charAt(str1, ndx1); 
      } 

      while (Character.isSpaceChar(char2) || char2 == '0') { 
       if (char2 == '0') { 
        zeroCount2++; 
       } else { 
        zeroCount2 = 0; 
       } 
       ndx2++; 
       char2 = charAt(str2, ndx2); 
      } 

      // process digits 

      boolean isDigitChar1 = CharUtil.isDigit(char1); 
      boolean isDigitChar2 = CharUtil.isDigit(char2); 

      if (isDigitChar1 && isDigitChar2) { 
       result = compareDigits(str1, ndx1, str2, ndx2); 
       if (result != 0) { 
        // not equals, return 
        return result; 
       } 
       // equal numbers 
       if (zeroCount1 != zeroCount2) { 
        return zeroCount1 - zeroCount2; 
       } 
      } 

      if (char1 == 0 && char2 == 0) { 
       // the end; the strings are the same, maybe compare ascii? 
       return zeroCount1 - zeroCount2; 
      } 

      // check when one of the numbers is just zeros 
      if (isDigitChar1 || isDigitChar2) { 
       if (zeroCount1 != zeroCount2) { 
        return zeroCount2 - zeroCount1; 
       } 
      } 

      // checks when both numbers are zero 
      if (zeroCount1 != zeroCount2) { 
       return zeroCount1 - zeroCount2; 
      } 

      // compare chars 
      if (ignoreCase) { 
       char1 = Character.toLowerCase(char1); 
       char2 = Character.toLowerCase(char2); 
      } 
      if (char1 < char2) { 
       return -1; 
      } 
      if (char1 > char2) { 
       return 1; 
      } 

      ndx1++; 
      ndx2++; 
     } 
    } 

    /** 
    * Safe charAt. 
    */ 
    private static char charAt(String s, int i) { 
     if (i >= s.length()) { 
      return 0; 
     } 
     return s.charAt(i); 
    } 
} 

가 예외를 throw를 다음 기능 :

@Override 
    public int compare(final T o1, final T o2) { 
     int result; 
     final MyObject obj1 = (MyObject) o1; 
     final MyObject obj2 = (MyObject) o2; 

        return  result = compareStringId(obj1.getStringId(),obj2.getStringId());   

    } 

private int compareStringId(final String Id1, final String Id2) { 
     return super.compare((T) Id1, (T) Id2); 
    } 

로컬 시스템에서는 정상적으로 작동하지만 실패합니다. 우리는 그 기계에 연결해서 그 이유를 알아낼 방법이 없습니다. 도움을 청하십시오.

+0

이 정보가 도움이됩니까? http://stackoverflow.com/questions/19325256/java-lang-illegalargumentexception-comparison-method-violates-its-general-contr – ppasler

+1

'super.compare ((T) ...)가 참조하는 수퍼 클래스는 무엇입니까? ? 왜 끈을'T '에 던지나요? Btw, 어떤 Java 버전을 로컬 및 서버에서 사용합니까? 만약 당신의 코드가 로컬에서 작동한다면 아마 다른 버전을 돌리고있을 것이고'ClassCastException'은'String'을'T'로 캐스팅 할 때 던져 질 것입니다. – Thomas

+0

또 다른 질문 : 일부 비교 자 코드를 게시했지만 어떻게 호출했는지 (즉, 어떤 코드가'Collections.sort (...) '를 호출하는지) 보여주지 않았습니다. – Thomas

답변

1

Comparator의 잘못된 구현 문제가있었습니다. Java 문서에 따르면 Comparator은 반사적이어야하며 추이 적이어야합니다. 이 경우 transivity는 보장되지 않았습니다. 이전의 Java 8은 큰 문제는 아니 었습니다. 즉, 정렬 구현 (MergeSort)은 예외를 발생시키지 않습니다. Java8은 기본 분류 구현을 TimSort으로 변경하여 유효하지 않은 계약이있는 비교 자에 훨씬 더 민감하므로 예외가 발생할 수 있습니다.

그러나 문제 해결에 많은 도움이되지는 않습니다. 같은 클래스의 최신 버전을 확인하는 방법은 here입니다. 비교기 계약을 지원하도록 업그레이드되었으며 일부 액센트의 경우에는 액센트에 대한 초기 지원은 물론 더 잘 작동합니다.

+1

고맙습니다. 수업을 업데이트했으며 현재 작동합니다. – TheHost