Java deaktiviert: Deaktivierte generische Array-Erstellung für varargs-Parameter

111

Ich habe Netbeans so eingestellt, dass in meinem Java-Code ungeprüfte Warnungen angezeigt werden, aber ich verstehe den Fehler in den folgenden Zeilen nicht:

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

Gibt:

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

Methodenquelle:

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

Was genau läuft schief und wie würde ich das beheben, da es vermutlich keine gute Idee ist, ungeprüfte Warnungen im Code zu belassen?

Ich habe vergessen zu erwähnen, aber ich benutze Java 7.

Bearbeiten : Auch ich sehe jetzt, dass die Methode Folgendes hat:

[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
quelle
17
Was auch immer Sie sonst noch tun, in Java Sie nicht ein neu erstelltes int - Array mit 0 s initialisieren müssen ...
Thomas Müller
1
@ ThomasMueller Guter Fang dort
Skiwi

Antworten:

165

Wie oben erwähnt, ist varargs in Java nur ein syntaktischer Zucker für Arrays und die implizite Erstellung eines Arrays am aufrufenden Standort. So

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

ist eigentlich

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

Wie Sie vielleicht wissen, new List<String>[]ist dies in Java aus Gründen, die in vielen anderen Fragen behandelt wurden, nicht zulässig , hängt jedoch hauptsächlich damit zusammen, dass Arrays ihren Komponententyp zur Laufzeit kennen und zur Laufzeit prüfen, ob hinzugefügte Elemente mit ihrer Komponente übereinstimmen Typ, aber diese Prüfung ist für parametrisierte Typen nicht möglich.

Anstatt zu scheitern, erstellt der Compiler das Array trotzdem. Es macht etwas Ähnliches:

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

Dies ist möglicherweise unsicher, aber nicht unbedingt unsicher. Die meisten varargs-Methoden durchlaufen einfach die varargs-Elemente und lesen sie. In diesem Fall ist der Laufzeittyp des Arrays egal. Dies ist bei Ihrer Methode der Fall. Da Sie mit Java 7 arbeiten, sollten Sie die @SafeVarargsAnnotation zu Ihrer Methode hinzufügen , damit diese Warnung nicht mehr angezeigt wird. Diese Annotation besagt im Grunde, dass sich diese Methode nur um die Typen der Elemente kümmert, nicht um den Typ des Arrays.

Es gibt jedoch einige varargs-Methoden, die den Laufzeittyp des Arrays verwenden. In diesem Fall ist es möglicherweise unsicher. Deshalb ist die Warnung da.

newacct
quelle
16
Vielen Dank, dass Sie SafeVarags nicht nur erwähnt haben, sondern uns auch mitgeteilt haben, wann wir es verwenden können.
KitsuneYMG
12
Wenn es für niemanden sofort offensichtlich war (wie für mich nicht), enthält Javadocs for @SafeVarargsein Beispiel für eine unsichere Methode docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs .html
michiakig
3
So @SafeVarargskann verwendet werden , wenn Ihre Methode nur verbraucht , die Elemente des Arrays und nicht (und wird es nie) produzieren Elemente in das Array setzen? Besondere Vorsicht ist geboten, wenn Sie das Array-Argument einem Feld zuweisen, das möglicherweise von anderen Methoden bearbeitet wird, da die Feststellung, dass keine unsicheren Operationen ausgeführt werden, möglicherweise nicht trivial ist.
neXus
13

Da der Java-Compiler eine implizite Array-Erstellung für Varargs verwendet und Java keine generische Array-Erstellung zulässt (da das Typargument nicht überprüfbar ist).

Der folgende Code ist korrekt (diese Vorgänge sind mit Arrays zulässig), daher ist eine ungeprüfte Warnung erforderlich:

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

Eine umfassende Erklärung finden Sie hier

Philip Voronov
quelle