以下代码是Dave Koelle's AlphanumComparator的编辑版本。编辑包含将空字符串排序到列表末尾的代码,或者在我的情况下将JTable
的底部排序。问题是java.lang.IllegalArgumentException: Comparison method violates its general contract!
发生。
为了解决我的问题,我调查了一下,发现比较器在正确的位置没有return 0;
的原因。我还在Java bug database中找到了一条评论
java.util.Arrays.sort和(间接)java.util.Collections.sort使用的排序算法已被替换。如果新的排序实现检测到违反Comparable合同的Comparable,则可能抛出IllegalArgumentException。以前的实现默默地忽略了这种情况。 如果需要以前的行为,则可以使用新的系统属性java.util.Arrays.useLegacyMergeSort来恢复先前的mergesort行为
import java.util.Comparator;
import javax.swing.JTable;
import javax.swing.SortOrder;
public class AlphanumComparator implements Comparator<String> {
JTable table;
public AlphanumComparator(JTable table) {
this.table = table;
}
private final boolean isDigit(char ch) {
return ch >= 48 && ch <= 57;
}
private final String getChunk(String s, int slength, int marker) {
StringBuilder chunk = new StringBuilder();
char c = s.charAt(marker);
chunk.append(c);
marker++;
if (isDigit(c)) {
while (marker < slength) {
c = s.charAt(marker);
if (!isDigit(c))
break;
chunk.append(c);
marker++;
}
} else {
while (marker < slength) {
c = s.charAt(marker);
if (isDigit(c))
break;
chunk.append(c);
marker++;
}
}
return chunk.toString();
}
public int compare(String s1, String s2) {
boolean swapInt = table.getRowSorter().getSortKeys().get(0).getSortOrder() == SortOrder.ASCENDING;
int thisMarker = 0;
int thatMarker = 0;
int s1Length = s1.length();
int s2Length = s2.length();
if(s1Length != 0 && s2Length != 0) {
while (thisMarker < s1Length && thatMarker < s2Length) {
String thisChunk = getChunk(s1, s1Length, thisMarker);
thisMarker += thisChunk.length();
String thatChunk = getChunk(s2, s2Length, thatMarker);
thatMarker += thatChunk.length();
int result = 0;
if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) {
int thisChunkLength = thisChunk.length();
result = thisChunkLength - thatChunk.length();
if (result == 0) {
for (int i = 0; i < thisChunkLength; i++) {
result = thisChunk.charAt(i) - thatChunk.charAt(i);
if (result != 0) {
return result;
}
}
}
} else {
result = thisChunk.compareTo(thatChunk);
}
if (result != 0)
return result;
}
return s1Length - s2Length;
} else {
if(swapInt) {
if(s1Length == 0) {
return 1;
} else {
return -1;
}
} else {
if(s1Length == 0) {
return -1;
} else {
return 1;
}
}
}
}
}
是否有人能够帮助解决我的问题,并解释为什么这个比较器违反了可比较合同
如果需要,可以使用异常堆栈跟踪
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.ComparableTimSort.mergeLo(ComparableTimSort.java:744)
at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:481)
at java.util.ComparableTimSort.mergeForceCollapse(ComparableTimSort.java:422)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:222)
at java.util.Arrays.sort(Arrays.java:1246)
at javax.swing.DefaultRowSorter.sort(DefaultRowSorter.java:607)
at javax.swing.DefaultRowSorter.setSortKeys(DefaultRowSorter.java:319)
at javax.swing.DefaultRowSorter.toggleSortOrder(DefaultRowSorter.java:480)
at javax.swing.plaf.basic.BasicTableHeaderUI$MouseInputHandler.mouseClicked(BasicTableHeaderUI.java:112)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:270)
at java.awt.Component.processMouseEvent(Component.java:6538)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6300)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4891)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4713)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4534)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
at java.awt.Container.dispatchEventImpl(Container.java:2280)
at java.awt.Window.dispatchEventImpl(Window.java:2750)
at java.awt.Component.dispatchEvent(Component.java:4713)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
答案 0 :(得分:6)
我认为问题是,当s2Length
为零时,您的代码永远不会检查s1Length
。您需要添加另一个检查以查看两个字符串是否为空,如下所示:
if(swapInt) {
if(s1Length == 0 && s2Length != 0) {
return 1;
} else if (s2Length == 0 && s1Length != 0) {
return -1;
} else {
return 0;
}
} else {
if(s1Length == 0 && s2Length != 0) {
return -1;
} else if (s2Length == 0 && s1Length != 0) {
return 1;
} else {
return 0;
}
}
您的当前实现返回1
或-1
,即使两个字符串为空(意味着它们必须比较为相等并返回零)。新的排序算法检测到此问题,并抛出异常。
注意:强>
您应该能够通过swapInt
int
1
或-1
getSortOrder
进一步简化此代码,具体取决于if(s1Length == 0 && s2Length != 0) {
return swapInt;
} else if (s2Length == 0 && s1Length != 0) {
return -swapInt;
} else {
return 0;
}
结果:
dplyr
答案 1 :(得分:2)
您的比较器确实:
if (s1Length != 0 && s2Length != 0) {
...
} else {
if (swapInt) {
if(s1Length == 0) {
return 1;
} else {
return -1;
}
} else {
if(s1Length == 0) {
return -1;
} else {
return 1;
}
}
}
因此,如果它没有进入if
块,则意味着至少有一个字符串为空。但两者都可能是空的。但在这种情况下,您的比较器仅返回-1或1。这意味着如果A和B都是空的,并且比较A和B导致-1,那么将B与A比较也将导致-1,因此A同时小于B且大于B.
用
启动你的else块if (s1Length == 0 && s2Length == 0) {
return 0;
}