Java non coché: création de tableau générique non cochée pour le paramètre varargs

112

J'ai configuré Netbeans pour afficher des avertissements non vérifiés dans mon code Java, mais je ne comprends pas l'erreur sur les lignes suivantes:

private List<String> cocNumbers;
private List<String> vatNumbers;
private List<String> ibans;
private List<String> banks;
...
List<List<String>> combinations = Utils.createCombinations(cocNumbers, vatNumbers, ibans);

Donne:

[unchecked] unchecked generic array creation for varargs parameter of type List<String>[]

Source de la méthode:

/**
 * Returns a list of all possible combinations of the entered array of lists.
 *
 * Example: [["A", "B"], ["0", "1", "2"]]
 * Returns: [["A", "0"], ["A", "1"], ["A", "2"], ["B", "0"], ["B", "1"], ["B", "2"]]
 *
 * @param <T> The type parameter
 * @param elements An array of lists
 * @return All possible combinations of the entered lists
 */
public static <T> List<List<T>> createCombinations(List<T>... elements) {
    List<List<T>> returnLists = new ArrayList<>();

    int[] indices = new int[elements.length];
    for (int i = 0; i < indices.length; i++) {
        indices[i] = 0;
    }

    returnLists.add(generateCombination(indices, elements));
    while (returnLists.size() < countCombinations(elements)) {
        gotoNextIndex(indices, elements);
        returnLists.add(generateCombination(indices, elements));
    }

    return returnLists;
}

Qu'est-ce qui ne va pas exactement et comment y remédier, car je suppose que laisser des avertissements non vérifiés dans le code n'est pas une bonne idée?

J'ai oublié de le mentionner, mais j'utilise Java 7.

Edit : Aussi je vois maintenant que la méthode a ce qui suit:

[unchecked] Possible heap pollution from parameterized vararg type List<T>
  where T is a type-variable:
    T extends Object declared in method <T>createCombinations(List<T>...)
skiwi
la source
17
Quoi que vous fassiez d'autre, en Java, vous n'avez pas besoin d'initialiser un tableau int nouvellement créé avec des 0 ...
Thomas Mueller
1
@ThomasMueller Bonne prise là
skiwi

Réponses:

165

Comme janoh.janoh mentionné ci-dessus, varargs en Java n'est qu'un sucre syntaxique pour les tableaux plus la création implicite d'un tableau sur le site appelant. Alors

List<List<String>> combinations =
    Utils.createCombinations(cocNumbers, vatNumbers, ibans);

est en fait

List<List<String>> combinations =
    Utils.createCombinations(new List<String>[]{cocNumbers, vatNumbers, ibans});

Mais comme vous le savez peut-être, new List<String>[]n'est pas autorisé en Java, pour des raisons qui ont été abordées dans de nombreuses autres questions, mais ont principalement à voir avec le fait que les tableaux connaissent leur type de composant à l'exécution et vérifient à l'exécution si les éléments ajoutés correspondent à son composant type, mais cette vérification n'est pas possible pour les types paramétrés.

Quoi qu'il en soit, plutôt que d'échouer, le compilateur crée toujours le tableau. Il fait quelque chose de similaire à ceci:

List<List<String>> combinations =
    Utils.createCombinations((List<String>[])new List<?>[]{cocNumbers, vatNumbers, ibans});

Ceci est potentiellement dangereux, mais pas nécessairement dangereux. La plupart des méthodes varargs itèrent simplement sur les éléments varargs et les lisent. Dans ce cas, il ne se soucie pas du type d'exécution du tableau. C'est le cas de votre méthode. Puisque vous êtes sur Java 7, vous devez ajouter l' @SafeVarargsannotation à votre méthode et vous n'obtiendrez plus cet avertissement. Cette annotation dit essentiellement que cette méthode ne se soucie que des types des éléments, pas du type du tableau.

Cependant, certaines méthodes varargs utilisent le type d'exécution du tableau. Dans ce cas, il est potentiellement dangereux. C'est pourquoi l'avertissement est là.

newacct
la source
16
Merci non seulement d'avoir mentionné SafeVarags, mais aussi de nous avoir indiqué quand nous pouvons l'utiliser.
KitsuneYMG
12
Si ce n'était immédiatement évident pour personne (comme ce n'était pas moi), les Javadocs pour @SafeVarargsont un exemple de méthode qui n'est pas sûre docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs .html
michiakig
3
@SafeVarargsPeut donc être utilisé lorsque votre méthode ne consomme que les éléments du tableau et ne produit pas (et ne produira jamais) d' éléments à mettre dans le tableau? Des précautions particulières doivent être prises si vous affectez l'argument tableau à un champ qui pourrait être manipulé par d'autres méthodes, car déterminer qu'aucune opération non sécurisée n'est effectuée sur celui-ci n'est peut-être pas trivial.
neXus
13

Parce que le compilateur java utilise une création de tableau implicite pour varargs, et que java n'autorise pas la création de tableau générique (car l'argument de type n'est pas réifiable).

Le code ci-dessous est correct (ces opérations sont autorisées avec les tableaux), un avertissement non coché est donc nécessaire:

public static <T> List<List<T>> createCombinations(List<T> ... lists) {
    ((Object[]) lists)[0] = new ArrayList<Integer>();
    // place your code here
}

Voir une explication complète ici

Philip Voronov
la source