Java8 List removeIf用法技巧
阿新 • • 發佈:2019-01-09
我們在寫業務程式碼時,經常需要擷取字串轉成List,然後再通過一個自定義的規則去刪減元素。通常使用的是
String.split(",")
的這種方式來切割字串,然後再用Arrays.asList(T...)
的方式建立List。然後再去處理List 裡面的內容。下面介紹一下1.8 裡面存在的坑。
字串切割
通常我們會使用Arrays.asList(T...)
來生成一個ArrayList。
List<String> compIdList = Arrays.asList(compIds.split(","));
當然也可以藉助Guava的API 來進行更強大的處理(Guava的用法不做過多介紹):
List<String> 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<E> 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<String> compIdList = new ArrayList<>(Arrays.asList(compIds.split(",")));
// 或者
List<String> compIdList = new ArrayList<>(Splitter.on(",").trimResults().splitToList());