1. 程式人生 > >Java8 List removeIf用法技巧

Java8 List removeIf用法技巧


我們在寫業務程式碼時,經常需要擷取字串轉成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());