누군가가 간단한 용어로 설명 할 수 있습니까? 왜이 코드에서 “비교 방법이 일반 계약을 위반합니다!”라는 예외가 발생합니까?
private int compareParents(Foo s1, Foo s2) {
if (s1.getParent() == s2) return -1;
if (s2.getParent() == s1) return 1;
return 0;
}
답변
당신의 비교기는 전 이적이지 않습니다.
하자 A
의 부모 B
및 B
의 부모 C
. 때문에 A > B
그리고 B > C
, 그것은 그 사건해야합니다 A > C
. 그러나 비교기가 A
및 C
에서 호출되면 0을 의미 A == C
합니다. 이는 계약을 위반하므로 예외가 발생합니다.
라이브러리가 이상하게 행동하기보다는 이것을 감지하고 알려주는 것이 좋습니다.
과도 성 요건을 충족시키는 한 가지 방법 은 직계 조상 만 보는 대신 체인 compareParents()
을 통과하는 getParent()
것입니다.
답변
이것이 내가이 오류를 Googled했을 때 얻은 것이므로 내 문제는
if (value < other.value)
return -1;
else if (value >= other.value)
return 1;
else
return 0;
는 value >= other.value
(분명히) 실제로해야 value > other.value
당신이 실제로 동일한 개체를 0을 반환 할 수 있도록.
답변
계약 위반은 종종 비교자가 객체를 비교할 때 정확하거나 일관된 값을 제공하지 않음을 의미합니다. 예를 들어, 문자열 비교를 수행하고 빈 문자열을 다음과 같이 끝까지 정렬하도록 할 수 있습니다.
if ( one.length() == 0 ) {
return 1; // empty string sorts last
}
if ( two.length() == 0 ) {
return -1; // empty string sorts last
}
return one.compareToIgnoreCase( two );
그러나 이것은 1과 2가 모두 비어있는 경우를 간과합니다.이 경우 잘못된 값이 반환되고 (0이 아닌 1이 일치 함) 비교기가이를 위반으로보고합니다. 다음과 같이 작성되어야합니다.
if ( one.length() == 0 ) {
if ( two.length() == 0 ) {
return 0; // BOth empty - so indicate
}
return 1; // empty string sorts last
}
if ( two.length() == 0 ) {
return -1; // empty string sorts last
}
return one.compareToIgnoreCase( two );
답변
귀하의 compareTo가 이론적으로 전이성을 유지하더라도 부동 소수점 산술 오류와 같은 미묘한 버그가 엉망이되는 경우가 있습니다. 그것은 나에게 일어났다. 이것은 내 코드였습니다.
public int compareTo(tfidfContainer compareTfidf) {
//descending order
if (this.tfidf > compareTfidf.tfidf)
return -1;
else if (this.tfidf < compareTfidf.tfidf)
return 1;
else
return 0;
}
전이 속성이 명확하게 유지되지만 어떤 이유로 든 IllegalArgumentException이 발생했습니다. 그리고 부동 소수점 산술의 작은 오류로 인해 전이 속성이 중단되어서는 안되는 반올림 오류가 발생합니다. 그래서 나는 실제로 작은 차이 0을 고려하기 위해 코드를 다시 작성했으며 작동했습니다.
public int compareTo(tfidfContainer compareTfidf) {
//descending order
if ((this.tfidf - compareTfidf.tfidf) < .000000001)
return 0;
if (this.tfidf > compareTfidf.tfidf)
return -1;
else if (this.tfidf < compareTfidf.tfidf)
return 1;
return 0;
}
답변
우리의 경우 실수로 s1과 s2의 비교 순서를 뒤집었기 때문에이 오류가 발생했습니다. 그러니 조심하십시오. 분명히 다음보다 훨씬 복잡했지만 이것은 예시입니다.
s1 == s2
return 0;
s2 > s1
return 1;
s1 < s2
return -1;
답변
Java는 엄격한 의미로 일관성을 검사하지 않으며 심각한 문제가 발생할 경우에만 알립니다. 또한 오류로부터 많은 정보를 제공하지 않습니다.
나는 내 분류기에서 일어나는 일에 당황하고 엄격한 일관성 검사기를 만들었습니다. 어쩌면 이것이 도움이 될 것입니다.
/**
* @param dailyReports
* @param comparator
*/
public static <T> void checkConsitency(final List<T> dailyReports, final Comparator<T> comparator) {
final Map<T, List<T>> objectMapSmallerOnes = new HashMap<T, List<T>>();
iterateDistinctPairs(dailyReports.iterator(), new IPairIteratorCallback<T>() {
/**
* @param o1
* @param o2
*/
@Override
public void pair(T o1, T o2) {
final int diff = comparator.compare(o1, o2);
if (diff < Compare.EQUAL) {
checkConsistency(objectMapSmallerOnes, o1, o2);
getListSafely(objectMapSmallerOnes, o2).add(o1);
} else if (Compare.EQUAL < diff) {
checkConsistency(objectMapSmallerOnes, o2, o1);
getListSafely(objectMapSmallerOnes, o1).add(o2);
} else {
throw new IllegalStateException("Equals not expected?");
}
}
});
}
/**
* @param objectMapSmallerOnes
* @param o1
* @param o2
*/
static <T> void checkConsistency(final Map<T, List<T>> objectMapSmallerOnes, T o1, T o2) {
final List<T> smallerThan = objectMapSmallerOnes.get(o1);
if (smallerThan != null) {
for (final T o : smallerThan) {
if (o == o2) {
throw new IllegalStateException(o2 + " cannot be smaller than " + o1 + " if it's supposed to be vice versa.");
}
checkConsistency(objectMapSmallerOnes, o, o2);
}
}
}
/**
* @param keyMapValues
* @param key
* @param <Key>
* @param <Value>
* @return List<Value>
*/
public static <Key, Value> List<Value> getListSafely(Map<Key, List<Value>> keyMapValues, Key key) {
List<Value> values = keyMapValues.get(key);
if (values == null) {
keyMapValues.put(key, values = new LinkedList<Value>());
}
return values;
}
/**
* @author Oku
*
* @param <T>
*/
public interface IPairIteratorCallback<T> {
/**
* @param o1
* @param o2
*/
void pair(T o1, T o2);
}
/**
*
* Iterates through each distinct unordered pair formed by the elements of a given iterator
*
* @param it
* @param callback
*/
public static <T> void iterateDistinctPairs(final Iterator<T> it, IPairIteratorCallback<T> callback) {
List<T> list = Convert.toMinimumArrayList(new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return it;
}
});
for (int outerIndex = 0; outerIndex < list.size() - 1; outerIndex++) {
for (int innerIndex = outerIndex + 1; innerIndex < list.size(); innerIndex++) {
callback.pair(list.get(outerIndex), list.get(innerIndex));
}
}
}
답변
제 경우에는 다음과 같은 일을하고있었습니다.
if (a.someField == null) {
return 1;
}
if (b.someField == null) {
return -1;
}
if (a.someField.equals(b.someField)) {
return a.someOtherField.compareTo(b.someOtherField);
}
return a.someField.compareTo(b.someField);
내가 확인하지 못한 것은 a.someField와 b.someField가 모두 null 일 때였습니다.