web-dev-qa-db-fra.com

UnsupportedOperationException sur Java.util.AbstractList.add

J'ai des problèmes pour faire fonctionner correctement un bloc de code. Je ne suis pas tout à fait sûr de ce que fait ce code (j'essaie d'obtenir un plugin obsolète pour fonctionner correctement avec notre serveur), je sais juste toutes les 20 minutes qu'il s'exécute et génère une erreur. Voici la section de 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<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());
}

}

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

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

L'erreur qu'il génère se produit toutes les 20 minutes deux fois avec 2 secondes entre les deux.

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)

Merci d'avance pour votre aide.

56
Erickj92

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

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

Cette méthode renvoie un List non redimensionnable soutenu par le tableau. De la documentation de cette méthode:

Renvoie une liste de taille fixe soutenue par le tableau spécifié. (Modifications de la liste renvoyée "écriture directe" dans le tableau.)

Pour utiliser un List redimensionnable (et en fait copier le contenu), utilisez ce qui suit:

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

Remarque: en général, lorsque vous voyez que UnsupportedOperationException est lancé par add, etc., c'est généralement une indication que 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) peut être utilisé comme optimisation mais être accidentellement transmis à des méthodes qui tentent de les modifier. Pour cette raison, il est recommandé que les méthodes fassent des copies défensives des collections avant de les modifier (à moins bien sûr que la modification de la collection soit l'effet secondaire prévu d'une méthode) - de cette façon, les appelants sont libres d'utiliser l'implémentation de collection la plus appropriée sans se soucier de savoir si elle a besoin être modifiable.

137
Paul Bellora

Je pense que j'ai résolu votre problème. Arrays.asList(item.getStock()) renvoie un liste de taille fixe basé sur le tableau qui lui est passé.

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

Au lieu de cela, vous devez faire new ArrayList(Arrays.asList(item.getStock())).

De cette façon, vous créez une nouvelle liste à laquelle vous pouvez ajouter.

25
Jivings

Le problème est que vous créez vos listes avec Arrays.asList . Selon le javadoc fourni, la liste renvoyée est une taille fixe, donc l'ajout ne serait pas pris en charge. Enveloppez la liste retournée dans un constructeur de copie pour arrayList et vous devriez être défini.

13
Charlie

La liste est Interface et vous ne pouvez pas y 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<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));

Ici l'objet tester et test2 sont parfaits, car ils font l'objet de classe ArrayList donc l'addition est possible
En test c'est juste une liste vide donc vous ne pouvez pas y ajouter d'élément.

Je faisais aussi la même erreur.

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

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

Le problème se situe dans la classe de l'objet liste qui est retourné par l'appel get. Il ne remplace pas les méthodes add de manière appropriée, et votre code utilise donc la méthode d'espace réservé fournie par AbstractList.

Il n'y a pas grand-chose de plus à dire sans savoir ce qu'est la classe de liste et (s'il s'agit de code personnalisé) voir le code source.

1
Stephen C

Dans mon cas, j'avais utilisé:

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

ce qui a rendu mon arraylist File abstrait. Utilisé à la place:

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

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

0
Benjamin Ronneling