天天看點

List在調用add、remove方法後報java.lang.UnsupportedOperationException

今天工作中碰到List對象調用add、remove方法竟然報錯,用了好幾年了盡然一直沒發現,不知道之前寫了多少bug。

在使用Arrays.asList()後調用add,remove這些method時出現java.lang.UnsupportedOperationException異常。這是由于Arrays.asList() 傳回java.util.Arrays A r r a y L i s t , 而 不 是 A r r a y L i s t 。 A r r a y s ArrayList,而不是ArrayList。Arrays ArrayList,而不是ArrayList。ArraysArrayList和ArrayList都是繼承AbstractList,remove,add等method在AbstractList中是預設throw UnsupportedOperationException而且不作任何操作。ArrayList override這些method來對list進行操作,但是Arrays$ArrayList沒有override remove(),add()等,是以throw UnsupportedOperationException。

Arrays源碼分析:

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }
           

Arrays.asList()方法傳回的是Arrays.ArrayList對象,而不是java.util.ArrayList對象。Arrays.ArrayList和java.util.ArrayList類都繼承AbstractList抽象類,Arrays.ArrayList類沒有重寫add、remove等方法,java.util.ArrayList類重寫了add、remove等方法。

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
           

使用Arrays.asList()方法傳回的對象去調用add、remove方法時,實際調用的是AbstractList抽象類的,該類的實作如下:

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

public E remove(int index) {
    throw new UnsupportedOperationException();
}
           

是以,使用Arrays.asList()傳回對象調用add、remove方法時直接報錯。

代碼如下:

public void updateUserTodayHasNoReadWord(String openId, String word, int flag) {
	String dateStr = TimeUtils.formatDateToStr(new Date(),"yyyyMMdd");
	String key = Constants.POCKET_YUEDU_USER_NO_READ_WORD_KEY + openId + "_" + dateStr;
	List<String> noReadWordList = new ArrayList<>();
	String noReadWord = redisTemplate.get(key);// 今日未讀單詞
	if (org.apache.commons.lang.StringUtils.isNotBlank(noReadWord)) {
		noReadWordList = Arrays.asList(noReadWord.split(","));
		noReadWordList.remove(word);
		noReadWord = String.join(",", noReadWordList);
		redisTemplate.setex(key, Constants.REDIS_TIME_OUT_ONE_DAY, noReadWord);
	}
}
           

運作代碼後,在調用remove()方法處報錯,java.lang.UnsupportedOperationException異常。

解決方法:

public void updateUserTodayHasNoReadWord(String openId, String word, int flag) {
	String dateStr = TimeUtils.formatDateToStr(new Date(),"yyyyMMdd");
	String key = Constants.POCKET_YUEDU_USER_NO_READ_WORD_KEY + openId + "_" + dateStr;
	List<String> noReadWordList = new ArrayList<>();
	String noReadWord = redisTemplate.get(key);// 今日未讀單詞
	if (org.apache.commons.lang.StringUtils.isNotBlank(noReadWord)) {
		noReadWordList = new ArrayList<>(Arrays.asList(noReadWord.split(",")));
		noReadWordList.remove(word);
		noReadWord = String.join(",", noReadWordList);
		redisTemplate.setex(key, Constants.REDIS_TIME_OUT_ONE_DAY, noReadWord);
	}
}
           

參考

When you call Arrays.asList it does not return a java.util.ArrayList. It returns a java.util.Arrays$ArrayList which is an immutable list. You cannot add to it and you cannot remove from it.

If you want a mutable list built from your array you will have to loop over the array yourself and add each element into the list in turn.

Even then your code won’t work because you’ll get an IndexOutOfBoundsException as you remove the elements from the list in the for loop. There are two options: use an Iterator which allows you to remove from the list as you iterate over it (my recommendation as it makes the code easier to maintain) or loop backwards over the loop removing from the last one downwards (harder to read).

You are using AbstractList. ArrayList and Arrays A r r a y L i s t a r e b o t h t y p e s o f A b s t r a c t L i s t . T h a t ′ s w h y y o u g e t U n s u p p o r t e d O p e r a t i o n E x c e p t i o n : A r r a y s ArrayList are both types of AbstractList. That&#x27;s why you get UnsupportedOperationException: Arrays ArrayListarebothtypesofAbstractList.That′swhyyougetUnsupportedOperationException:ArraysArrayList does not override remove(int) so the method is called on the superclass, AbstractList, which is what is throwing the exception because this method is not implemented on that class (the reason being to allow you to build immutable subclasses).

另外:List轉換成字元串并加入分隔符,可以StringUtils的join方法

public String listToString(List list, char separator) {

   org.apache.commons.lang.StringUtils.join(list.toArray(),separator);

}

轉載自:http://blog.csdn.net/fygkchina/article/details/32329293

————————————————

版權聲明:本文為CSDN部落客「劉彥民」的原創文章,遵循 CC 4.0 BY-SA 版權協定,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/u014740338/article/details/78534200