UnsupportedOperationException в java.util.AbstractList.add - PullRequest
55 голосов
/ 17 февраля 2012

У меня проблемы с получением блока кода для правильной работы. Я не совсем уверен, ЧТО делает этот код (я пытаюсь получить плагин, который устарел для правильной работы с нашим сервером), я просто знаю, что каждые 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)

Заранее спасибо за любую помощь.

Ответы [ 5 ]

132 голосов
/ 17 февраля 2012

Вы используете 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.emptyList или Collections.singletonList (которые возвращают немодифицируемые коллекции) могут использоваться в качестве оптимизаций, но случайно могут передаваться в методы, которые пытаются их изменить.По этой причине хорошей практикой для методов является создание защитных копий коллекций перед их изменением (если, конечно, изменение коллекции не является побочным эффектом метода) - таким образом вызывающие могут свободно использовать наиболее подходящую реализацию коллекции, не беспокоясь о том, нужна ли онабыть модифицируемым.

23 голосов
/ 17 февраля 2012

Я думаю, что я решил вашу проблему.Arrays.asList(item.getStock()) возвращает список фиксированного размера на основе переданного ему массива.

Это означает, что вы не можете добавить к нему больше элементов.

Вместо этого вы должны сделать new ArrayList(Arrays.asList(item.getStock())).

Таким образом, вы создаете новый список, к которому вы можете добавить.

13 голосов
/ 17 февраля 2012

Проблема в том, что вы создаете свои списки с помощью Arrays.asList . Согласно предоставленному javadoc, возвращаемый список имеет фиксированный размер, поэтому добавление не будет поддерживаться. Оберните возвращенный список в конструктор копирования для arrayList, и вы должны быть установлены.

6 голосов
/ 07 августа 2016

Список - это интерфейс, и вы не можете добавлять в него значение, пока он не станет экземпляром 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));

Здесь Object test и test2 идеальны, поскольку они являются объектом класса ArrayList , поэтому добавление возможно
В то время как в test3 это просто пустой список, поэтому вы не можете добавить в него элемент.

Я тоже делал ту же ошибку.

Вот мое предложение. Используйте ArrayList, когда вам нужно выполнять такие операции, как добавление или удаление, используйте список только для справочных целей.

 Map<ItemInfo, ArrayList<Integer>> itemStockMap = Collections.synchronizedMap(new HashMap<ItemInfo, ArrayList<Integer>>());
1 голос
/ 17 февраля 2012

Проблема в классе объекта списка, который возвращается вызовом get. Он не переопределяет методы add надлежащим образом, и поэтому ваш код использует метод-заполнитель, предоставленный AbstractList.

Мы не можем сказать намного больше, не зная, что такое класс списка, и (если это пользовательский код), увидев исходный код.

...