java.util.AbstractList.add中的UnsupportedOperationException

时间:2012-02-16 22:56:27

标签: java list exception abstract-class

我遇到了让代码块正常运行的问题。我不完全确定这个代码做了什么(我试图让一个过时的插件与我们的服务器一起正常工作),我只知道每运行20分钟并抛出一个错误。以下是发生问题的代码部分:

public class DynamicThread extends Thread {
private LocalShops plugin = null;


public DynamicThread(ThreadGroup tgroup, String tname, LocalShops plugin) {
    super(tgroup, tname);
    this.plugin = plugin;
}

public void run() {
    Map<ItemInfo, List<Integer>> itemStockMap = Collections.synchronizedMap(new HashMap<ItemInfo, List<Integer>>());

    //Dump all the shop stock data into the map.
    for ( Shop shop : plugin.getShopManager().getAllShops() ) {
        for ( InventoryItem item : shop.getItems() ) {
            if (itemStockMap.containsKey(item.getInfo()))
                itemStockMap.get(item.getInfo()).add(item.getStock()); //Where error happens
            else
                itemStockMap.put(item.getInfo(), Arrays.asList(item.getStock()));     
        }
    }
    for(ItemInfo item : itemStockMap.keySet()) {
        List<Integer> stockList = GenericFunctions.limitOutliers(itemStockMap.get(item));
        //remove the map before re-adding it
        if (DynamicManager.getPriceAdjMap().containsKey(item)) 
            DynamicManager.getPriceAdjMap().remove(item);

        //Get the overall stock change for a given item and then calculate the adjustment given the volatility
        int deltaStock = GenericFunctions.getSum(stockList) - Config.getGlobalBaseStock();
        DynamicManager.getPriceAdjMap().put(item, GenericFunctions.getAdjustment(Config.getGlobalVolatility(), deltaStock)); 
    }

    Bukkit.getServer().getScheduler().callSyncMethod(plugin, plugin.getShopManager().updateSigns());
}

}

错误发生在第42行,即:

                itemStockMap.get(item.getInfo()).add(item.getStock());

它输出的错误每20分钟发生两次,中间为2秒。

2012-02-16 16:53:25 [INFO] Launch Dynamic Thread
2012-02-16 16:53:25 [SEVERE] Exception in thread "dynamic" 
2012-02-16 16:53:25 [SEVERE] java.lang.UnsupportedOperationException
2012-02-16 16:53:25 [SEVERE] at java.util.AbstractList.add(AbstractList.java:131)
2012-02-16 16:53:25 [SEVERE] at java.util.AbstractList.add(AbstractList.java:91)
2012-02-16 16:53:25 [SEVERE] at       com.milkbukkit.localshops.threads.DynamicThread.run(DynamicThread.java:42)

2012-02-16 16:53:27 [INFO] Launch Dynamic Thread
2012-02-16 16:53:27 [SEVERE] Exception in thread "dynamic" 
2012-02-16 16:53:27 [SEVERE] java.lang.UnsupportedOperationException
2012-02-16 16:53:27 [SEVERE] at java.util.AbstractList.add(AbstractList.java:131)
2012-02-16 16:53:27 [SEVERE] at java.util.AbstractList.add(AbstractList.java:91)
2012-02-16 16:53:27 [SEVERE] at     com.milkbukkit.localshops.threads.DynamicThread.run(DynamicThread.java:42)

提前感谢您的帮助。

7 个答案:

答案 0 :(得分:128)

您正在使用Arrays.asList()Map此处创建列表:

itemStockMap.put(item.getInfo(), Arrays.asList(item.getStock()));  

此方法返回数组支持的不可调整大小的List。从该方法的文档:

  

返回由指定数组支持的固定大小的列表。 (改为   返回的列表“直写”到数组。)

要使用可调整大小的List(并实际复制内容),请使用以下内容:

itemStockMap.put(
        item.getInfo(),
        new ArrayList<Integer>(Arrays.asList(item.getStock()))
); 

注意:一般情况下,当UnsupportedOperationException等人看到add被抛出时,通常会显示某些代码正在尝试修改不可调整大小的代码或不可修改的集合。

例如,Collections.emptyListCollections.singletonList(返回不可修改的集合)可以用作优化,但会意外地传递给尝试修改它们的方法。因此,在修改集合之前制作防御性集合的方法是很好的做法(除非当然修改集合是一种方法的预期副作用) - 这样调用者可以自由地使用最合适的集合实现而不必担心它是否需要可以修改。

答案 1 :(得分:23)

我想我已经解决了你的问题。 Arrays.asList(item.getStock())根据传递给它的数组返回固定大小列表

这意味着您无法向其中添加更多元素。

相反,你应该new ArrayList(Arrays.asList(item.getStock()))

这样您就可以创建一个可以添加的新列表。

答案 2 :(得分:13)

问题是您使用Arrays.asList创建了列表。根据提供的javadoc,返回的列表是固定大小,因此不支持添加。将返回的列表包装在arrayList的复制构造函数中,您应该进行设置。

答案 3 :(得分:4)

列表是接口,除非它是ArrayList的实例(接口应该由某个类实现),否则不能在其中添加值。

例如:

    List<Integer> test = new ArrayList<>();
    test.add(new Integer(2));

    ArrayList<Integer> test2 = new ArrayList<>();
    test2.add(new Integer(2));

    List<Integer> test3 = Collections.EMPTY_LIST;
    test3.add(new Integer(2));

这里对象测试 test2 是完美的,因为它们是 ArrayList类的对象,所以可以添加其中strong> test3 它只是空列表,因此您无法在其中添加元素。

我也犯了同样的错误。

当您必须执行添加或删除操作时,我的建议使用ArrayList,仅用于参考目的。

 Map<ItemInfo, ArrayList<Integer>> itemStockMap = Collections.synchronizedMap(new HashMap<ItemInfo, ArrayList<Integer>>());

答案 4 :(得分:3)

就我而言,我曾经使用过:

List<File> removeFilesList= Collections.emptyList();

这使我的File arraylist抽象化。改用:

List<File> removeFilesList= new ArrayList<>();

并且错误已修复。

答案 5 :(得分:1)

问题出在get调用返回的列表对象的类中。它没有适当地覆盖add方法,因此您的代码使用AbstractList提供的占位符方法。

如果不知道列表类是什么,并且(如果是自定义代码)看到源代码,我们就可以说更多。

答案 6 :(得分:-2)

我使用 getter 来获取列表,但它返回的是列表的固定大小,因此您无法添加新元素,

你应该这样做

new ArrayList(Arrays.asList(item.getStock()))