我们在写业务代码时,经常需要截取字符串转成List,然后再通过一个自定义的规则去删减元素。通常使用的是String.split(",")的这种方式来切割字符串,然后再用Arrays.asList(T...)的方式创建List。然后再去处理List 里面的内容。下面介绍一下1.8 里面存在的坑。
字符串切割
通常我们会使用Arrays.asList(T...)来生成一个ArrayList。
List compIdList = Arrays.asList(compIds.split(","));
当然也可以借助Guava的API 来进行更强大的处理(Guava的用法不做过多介绍):
List compIdList = Splitter.on(",").trimResults().splitToList(compIds);
使用List.removeIf API 剔除元素
List 创建完之后,看了下开发工具提示了个removeIf()方法。看了下里面的实现,是1.8 开始提供了,于是就尝了个鲜。在Collection 接口中的实现如下:
default boolean removeIf(Predicate super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
看上面的代码也没什么问题,于是就使用了。
compIdList.removeIf(tempCompId -> {
if (判断逻辑) {
return true;
}
return false;
});
运行之后发现血崩了,结果如下:
java.lang.UnsupportedOperationException: null
at java.util.AbstractList.remove(AbstractList.java:161)
at java.util.AbstractList$Itr.remove(AbstractList.java:374)
at java.util.Collection.removeIf(Collection.java:415)
问题解决
经过再次查看代码发现,Arrays.asList(T...)的方式和Guava的方式 new 出来的类都是静态内部类。下面以Arrays.asList 为例介绍。
它的 List 实现为:java.util.Arrays.ArrayList,迭代器实现使用的是继承的 java.util.AbstractList 中的 iterator():
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
而 java.util.AbstractList 中的 remove实现如下:
public E remove(int index) {
throw new UnsupportedOperationException();
}
意思就是说 AbstractList 的子类只有重写了 remove(int index) 才可以使用 removeIf() 方法。而上面 2 种 List都没有重写,因此报错。
解决办法也很简单,就是再在外面包一层可变的 java.util.ArrayList 即可。
List compIdList = new ArrayList<>(Arrays.asList(compIds.split(",")));
// 或者
List compIdList = new ArrayList<>(Splitter.on(",").trimResults().splitToList());