昨天遇到个问题,对字符串按照自然顺序排序,比如说"abd03156"->"01356abd"
最开始是这么写的:
val toList = newValue.toList()
Collections.sort(toList)
var result = ""
for (i in toList) {
result += i
}
newValue设置的初始值为“0“
上面的代码在7.0的手机上崩溃了,在8.0和9.0的手机上木有问题
报错信息如下:
Caused by: java.lang.UnsupportedOperationException
at java.util.AbstractList.set(AbstractList.java:681)
at java.util.AbstractList$FullListIterator.set(AbstractList.java:143)
at java.util.Collections.sort(Collections.java:1882)
at com.test.databindingdemo.MainActivity$$special$$inlined$observable$1.afterChange(Delegates.kt:73)
at kotlin.properties.ObservableProperty.setValue(ObservableProperty.kt:41)
at com.test.databindingdemo.MainActivity.setGetServerDataStatus(MainActivity.kt)
at com.test.databindingdemo.MainActivity.onCreate(MainActivity.kt:65)
后来临时改成了这样就木有问题了。
val toCharArray = newValue.toCharArray()
Arrays.sort(toCharArray)
val result = String(toCharArray)
可是为什么呢?看日志应该是Collections的sort函数有问题,看代码发现个提示
猜测:kotlin的toList函数的返回值是个不可更改的List,如果需要返回可更改的List需要使用toMutableList,但是为什么在8.0和9.0的手机上木有问题呢?
看Collections的sort函数代码
public static <T> void sort(List<T> list, Comparator<? super T> c) {
// BEGIN Android-changed: Compat behavior for apps targeting APIs <= 25.
// list.sort(c);
int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
if (targetSdkVersion > 25) {
list.sort(c);
} else {
// Compatibility behavior for API <= 25. http://b/33482884
if (list.getClass() == ArrayList.class) {
Arrays.sort((T[]) ((ArrayList) list).elementData, 0, list.size(), c);
return;
}
Object[] a = list.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<T> i = list.listIterator();
for (int j = 0; j < a.length; j++) {
i.next();
i.set((T) a[j]);
}
}
// END Android-changed: Compat behavior for apps targeting APIs <= 25.
}
7.0的sort代码和上面else里的代码一样
public static <T extends Comparable<? super T>> void sort(List<T> list) {
if (list.getClass() == ArrayList.class) {
Arrays.sort(((ArrayList) list).elementData, 0, list.size());
return;
}
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
单个字符的字符串toList转换成的对象为Collections$SingletonList
而多字符的字符串toList转换成的对象为ArrayList
7.1(sdk 25)以上的代码里是执行的List的sort方法,如果是Collections$SingletonList,那就执行Collections$SingletonList.sort()方法,如果是ArrayList,那么就执行ArrayList的sort()方法。Collections$SingletonList这个类重写了sort方法(空实现,方法里啥都没有),所以不会造成崩溃,一个字符不用排序啊!
但是7.1及以下的代码里用Iterator做里遍历,而这个遍历导致里崩溃。再说下为什么会崩溃,Iterator的set方法如下,调用里AbstractList的set方法,这个方法直接抛出了异常。
public void set(E object) {
if (expectedModCount == modCount) {
try {
AbstractList.this.set(lastPosition, object);
} catch (IndexOutOfBoundsException e) {
throw new IllegalStateException();
}
} else {
throw new ConcurrentModificationException();
}
}