"비교 방식은 일반 계약을 위반한다!"
누가 간단한 말로 설명해줄 수 있을까, 이 코드는 왜 '비교 방식이 일반 계약을 위반한다!'라는 예외를 두는지, 그리고 어떻게 고쳐야 하는지.
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그리고C0이 돌아온다는 뜻이야A == C이것은 계약을 위반하고 따라서 예외를 둔다.
이것을 감지하고 알려 주는 것은 도서관이 비정상적으로 행동하기보다는 오히려 친절하다.
다음에서 Transitability 요건을 충족할 수 있는 한 가지 방법compareParents()그 길을 가로지르는 것이다.getParent()직계 조상만 보지 않고 쇠사슬을 매다
내가 이 오류를 검색했을 때 받은 것이 이것이기 때문에, 내 문제는 내가 가지고 있는 것이었어.
if (value < other.value)
return -1;
else if (value >= other.value)
return 1;
else
return 0;
그value >= other.value실제로 그래야 한다value > other.value0을 동일한 객체로 반환할 수 있도록.
계약 위반은 종종 대조군이 사물을 비교할 때 정확하거나 일관된 값을 제공하지 않는다는 것을 의미한다.예를 들어, 문자열 비교를 수행하고 빈 문자열을 강제로 다음과 같이 정렬할 수 있다.
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 );
비록 당신의 비교가 이론상으로는 transactivity를 유지한다고 해도, 때때로 미묘한 벌레들이 일을 망친다...부동 소수점 산술 오차 등나한테 일어난 일이야 이게 내 암호야
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;
}
그 전이적 재산은 분명히 가지고 있지만, 어떤 이유에서인지 나는 '불법적 주장'을 받고 있었다.예외.그리고 그것은 부동소수점 산술의 작은 오류로 인해, 전이적 속성을 그들이 해서는 안 되는 곳에서 깨지게 하는 반올림 오류로 밝혀졌다.그래서 나는 정말 작은 차이 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;
}
VM 구성을 편집하는 것이 나에게 효과가 있었다.
-Djava.util.Arrays.useLegacyMergeSort=true
우리의 경우 s1과 s2의 비교 순서를 실수로 뒤집었기 때문에 이 오류가 발생하고 있었다.그러니 조심해.그것은 분명히 다음 사항들보다 훨씬 더 복잡했지만, 이것은 예증이다.
s1 == s2
return 0;
s2 > s1
return 1;
s1 < s2
return -1;
내 경우에는 다음과 같은 일을 하고 있었다.
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가 둘 다 무효일 때였다.
자바는 엄격한 의미에서 일관성을 점검하지 않고, 심각한 문제가 발생했을 때만 알려준다.또한 그것은 당신에게 오류로부터 많은 정보를 주지 않는다.
나는 내 정렬기에서 무슨 일이 일어나고 있는지 어리둥절했고 엄격한 일관성 체커를 만들었어. 이것이 아마 너에게 도움이 될 거야.
/**
* @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));
}
}
}
종종 반복되는 null 값 확인이 수행되는 코드 조각에서 이러한 현상이 발생하는 것을 본 적이 있다.
if(( A==null ) && ( B==null )
return +1;//WRONG: two null values should return 0!!!
만약compareParents(s1, s2) == -1그때compareParents(s2, s1) == 1예정되어 있다.네 코드로는 항상 사실이 아니다.
구체적으로 말하면s1.getParent() == s2 && s2.getParent() == s1그것은 단지 가능한 문제들 중 하나이다.
내 경우는 무한종류였다.즉 처음에는 조건에 따라 선이 위로 이동한 다음, 같은 선이 같은 곳으로 내려간다는 것이다.나는 그 끝에 모호하지 않게 선의 질서를 확립하는 조건을 하나 더 추가했다.
다음과 같은 개체 데이터를 비교할 수 없음:s1.getParent() == s2- 이렇게 하면 객체 참조를 비교할 수 있다.재정의해야 한다.equals function Foo 반을 이 Foo 반처럼 비교해보자.s1.getParent().equals(s2)
나는 같은 문제에 직면했고 그것을 해결했다.
//This this your code
private int compareParents(Foo s1, Foo s2) {
if (s1.getParent() == s2) return -1;
if (s2.getParent() == s1) return 1;
return 0;
}
그 위반은 서로 다른 것들을 비교하는 것이다.
//acceptable
compare between s1.getParent() and s2.getParent()
//acceptable
compare between s1 and s2
//NOT acceptable
compare between s1 and s2.getParent()
//NOT acceptable
compare between s1.getParent() and s2
내 코드에서, 나는 그들의 조정으로 주소를 분류하고 싶었다.대조약에서는 X와 X가 아닌 X와 Y를 (실수로) 비교했다.
//My code:
private void sortBasedOnX(){
//addresses is a list of addresses where each address has X and Y
addresses.sort((o1, o2) -> {
String a = o1.getAddress().getX();
String b = o2.getAddress().getY(); //<-- this is supposed to be getX
return Integer.parseInt(a)-Integer.parseInt(b);
});
}
//acceptable
compare between o1.getAddress().getX() and o1.getAddress().getX()
//acceptable
compare between o1.getAddress().getY() and o1.getAddress().getY()
//NOT acceptable
compare between o1.getAddress().getX() and o1.getAddress().getY()
//NOT acceptable
compare between o1.getAddress().getX() and o1.getAddress()
//NOT acceptable
compare between o1.getAddress().getX() and o1
참조URL: https://stackoverflow.com/questions/8327514/comparison-method-violates-its-general-contract
'programing' 카테고리의 다른 글
| (VueJS) Vuex Getter는 다른 모듈 상태 변경을 기반으로 업데이트되어야 함 (0) | 2022.05.21 |
|---|---|
| Vue.js 독립 실행형에서 핸즈통트 가능 (0) | 2022.05.21 |
| Nuxt / Vue - 돌연변이 처리기 외부에서 vuex 저장소 상태 변경 안 함 (0) | 2022.05.21 |
| if-return-return 또는 if-else-return을 사용하는 것이 더 효율적인가? (0) | 2022.05.21 |
| v-for 루프를 사용하여 다른 색상 배경 바인딩 (0) | 2022.05.21 |