Java deselezionato: creazione di array generici non controllati per il parametro varargs


112

Ho impostato Netbeans in modo da mostrare avvisi non controllati nel mio codice Java, ma non riesco a comprendere l'errore nelle seguenti righe:

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);

dà:

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

Fonte del metodo:

/**
 * 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;
}

Cosa sta andando esattamente storto e come dovrei risolverlo, poiché suppongo che lasciare avvisi non controllati nel codice non sia una buona idea?

Ho dimenticato di menzionare, ma sto usando Java 7.

Modifica : inoltre vedo ora che il metodo ha quanto segue:

[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>...)

17
Qualunque altra cosa tu faccia, in Java non è necessario inizializzare un array int appena creato con 0 ...
Thomas Mueller

1
@ThomasMueller Buona cattura lì
skiwi

Risposte:


165

Come janoh.janoh menzionato sopra, varargs in Java è solo uno zucchero sintattico per gli array più la creazione implicita di un array nel sito chiamante. Così

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

è effettivamente

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

Ma come forse saprai, new List<String>[]non è consentito in Java, per ragioni che sono state trattate in molte altre domande, ma principalmente hanno a che fare con il fatto che gli array conoscono il loro tipo di componente in fase di esecuzione e controllano in fase di esecuzione se gli elementi aggiunti corrispondono al suo componente tipo, ma questo controllo non è possibile per i tipi parametrizzati.

Comunque, piuttosto che fallire, il compilatore crea ancora l'array. Fa qualcosa di simile a questo:

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

Questo è potenzialmente pericoloso, ma non necessariamente pericoloso. La maggior parte dei metodi varargs semplicemente itera sugli elementi varargs e li legge. In questo caso, non si preoccupa del tipo di runtime dell'array. Questo è il caso del tuo metodo. Dato che sei su Java 7, dovresti aggiungere l' @SafeVarargsannotazione al tuo metodo e non riceverai più questo avviso. Questa annotazione fondamentalmente dice che questo metodo si preoccupa solo dei tipi di elementi, non del tipo di array.

Tuttavia, esistono alcuni metodi varargs che utilizzano il tipo di runtime dell'array. In questo caso, è potenzialmente pericoloso. Ecco perché c'è l'avvertimento.


16
Grazie non solo per aver menzionato SafeVarags, ma anche per averci detto quando possiamo usarlo.
KitsuneYMG

12
Se non era immediatamente ovvio per nessuno (come non lo era per me), il Javadocs per @SafeVarargsha un esempio di un metodo che non è sicuro docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs .html
michiakig

3
Quindi @SafeVarargspuò essere usato quando il tuo metodo consuma solo gli elementi dell'array e non produce (e non lo farà mai) elementi da inserire nell'array? È necessario prestare particolare attenzione se si assegna l'argomento della matrice a un campo che potrebbe essere manipolato da altri metodi perché determinare che non ci sono operazioni non sicure eseguite su di esso potrebbe non essere banale.
neXus

13

Perché il compilatore java utilizza una creazione di array implicita per varargs e java non consente una creazione di array generica (perché l'argomento di tipo non è modificabile).

Il codice seguente è corretto (queste operazioni sono consentite con gli array), quindi è necessario un avviso non selezionato:

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

Vedi una spiegazione completa qui

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.