116 votes

UnsupportedOperationException à java.util.AbstractList.add

Je rencontre des problèmes pour exécuter correctement un bloc de code. Je ne suis pas totalement sûr de CE QUE fait ce code (j'essaie de faire fonctionner correctement un plugin obsolète avec notre serveur), je sais juste qu'il s'exécute toutes les 20 minutes et génère une erreur. Voici la section du code où le problème se produit :

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> itemStockMap = Collections.synchronizedMap(new HashMap>());

    //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 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());
}

}

L'erreur se produit à partir de la ligne 42, qui est :

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

L'erreur se produit toutes les 20 minutes deux fois avec 2 secondes d'intervalle.

2012-02-16 16:53:25 [INFO] Lancer le fil dynamique
2012-02-16 16:53:25 [GRAVE] Exception dans le fil "dynamique"
2012-02-16 16:53:25 [GRAVE] java.lang.UnsupportedOperationException
2012-02-16 16:53:25 [GRAVE] à java.util.AbstractList.add(AbstractList.java:131)
2012-02-16 16:53:25 [GRAVE] à java.util.AbstractList.add(AbstractList.java:91)
2012-02-16 16:53:25 [GRAVE] à       com.milkbukkit.localshops.threads.DynamicThread.run(DynamicThread.java:42)

2012-02-16 16:53:27 [INFO] Lancer le fil dynamique
2012-02-16 16:53:27 [GRAVE] Exception dans le fil "dynamique"
2012-02-16 16:53:27 [GRAVE] java.lang.UnsupportedOperationException
2012-02-16 16:53:27 [GRAVE] à java.util.AbstractList.add(AbstractList.java:131)
2012-02-16 16:53:27 [GRAVE] à java.util.AbstractList.add(AbstractList.java:91)
2012-02-16 16:53:27 [GRAVE] à     com.milkbukkit.localshops.threads.DynamicThread.run(DynamicThread.java:42)

243voto

Paul Bellora Points 26524

Vous utilisez Arrays.asList() pour créer les listes dans la Map ici:

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

Cette méthode renvoie une List non redimensionnable soutenue par le tableau. Voici ce que dit la documentation de cette méthode:

Renvoie une liste de taille fixe soutenue par le tableau spécifié. (Les modifications apportées à la liste retournée "s'écrivent" dans le tableau.)

Pour utiliser une List redimensionnable (et effectivement copier les contenus), utilisez ce qui suit:

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

Remarque: en général, lorsque vous voyez une UnsupportedOperationException levée par add, etc., cela indique souvent qu'un code essaie de modifier une collection non redimensionnable ou non modifiable.

Par exemple, Collections.emptyList ou Collections.singletonList (qui renvoient des collections non modifiables) peuvent être utilisées comme optimisations mais peuvent être accidentellement transmises à des méthodes qui essaient de les modifier. Pour cette raison, il est bon que les méthodes effectuent des copies défensives des collections avant de les modifier (sauf bien sûr si la modification de la collection est l'effet secondaire prévu de la méthode) - de cette manière, les appelants sont libres d'utiliser l'implémentation de collection la plus appropriée sans se soucier de savoir si elle doit être modifiable.

51voto

Jivings Points 10892

Je pense avoir compris votre problème. Arrays.asList(item.getStock()) renvoie une liste de taille fixe basée sur le tableau qui lui est passé.

Cela signifie que vous ne pouvez pas y ajouter d'autres éléments.

Vous devriez plutôt faire new ArrayList(Arrays.asList(item.getStock())).

De cette manière, vous créez une nouvelle liste à laquelle vous pouvez ajouter.

18voto

Charlie Points 3871

Le problème est que vous créez vos listes avec Arrays.asList. Selon la javadoc fournie, la liste retournée est de taille fixe, donc l'ajout serait non pris en charge. Enveloppez la liste retournée dans un constructeur de copie pour arrayList et vous devriez être prêt.

14voto

Dans mon cas, j'avais utilisé :

List removeFilesList= Collections.emptyList();

ce qui rendait mon ArrayList de fichiers abstrait. J'ai plutôt utilisé :

List removeFilesList= new ArrayList<>();

Et l'erreur a été corrigée.

10voto

Lokesh Tiwari Points 6168

La liste est une Interface et vous ne pouvez pas ajouter de valeur tant qu'elle n'est pas une instance d'ArrayList (l'interface doit être implémentée par une classe)

Par exemple:

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

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

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

Ici, les objets test et test2 sont parfaits, car ce sont des objets de la classe ArrayList, donc l'ajout est possible
Alors que dans test3, c'est juste une liste vide alors vous ne pouvez pas ajouter d'élément dedans.

J'ai aussi fait la même erreur.

Voici ma suggestion: Utilisez ArrayList lorsque vous devez effectuer des opérations comme ajouter ou supprimer, utilisez List uniquement à des fins de référence.

 Map> itemStockMap = Collections.synchronizedMap(new HashMap>());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X