Java niezaznaczona: niezaznaczone tworzenie ogólnych tablic dla parametru varargs


112

Ustawiłem Netbeans tak, aby wyświetlał niesprawdzone ostrzeżenia w moim kodzie Java, ale nie rozumiem błędu w następujących wierszach:

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

Daje:

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

Źródło metody:

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

Co dokładnie idzie nie tak i jak mam to naprawić, skoro wydaje mi się, że pozostawienie w kodzie niezaznaczonych ostrzeżeń nie jest dobrym pomysłem?

Zapomniałem o tym wspomnieć, ale używam Java 7.

Edycja : Widzę również, że metoda ma następujące cechy:

[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
Cokolwiek robisz, w Javie nie musisz inicjować nowo utworzonej tablicy int z zerami ...
— Thomas Mueller

1
@ThomasMueller Dobry chwyt
— skiwi

Odpowiedzi:


165

Jak wspomniano powyżej w janoh.janoh, varargs w Javie to tylko cukier składniowy dla tablic oraz niejawne tworzenie tablicy w witrynie wywołującej. Więc

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

jest aktualne

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

Ale jak być może wiesz, new List<String>[]nie jest dozwolone w Javie z powodów, które zostały omówione w wielu innych pytaniach, ale głównie z faktu, że tablice znają swój typ komponentu w czasie wykonywania i sprawdzają w czasie wykonywania, czy dodane elementy pasują do swojego komponentu typ, ale to sprawdzenie nie jest możliwe w przypadku typów sparametryzowanych.

W każdym razie, zamiast zawieść, kompilator nadal tworzy tablicę. Robi coś podobnego do tego:

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

Jest to potencjalnie niebezpieczne, ale niekoniecznie niebezpieczne. Większość metod varargs po prostu iteruje po elementach varargs i czyta je. W tym przypadku nie dba o typ środowiska wykonawczego tablicy. Tak jest w przypadku Twojej metody. Ponieważ korzystasz z Javy 7, powinieneś dodać @SafeVarargsadnotację do swojej metody, a nie będziesz już otrzymywać tego ostrzeżenia. Ta adnotacja zasadniczo mówi, że ta metoda dba tylko o typy elementów, a nie o typ tablicy.

Jednak istnieje kilka metod varargs, które używają typu środowiska wykonawczego tablicy. W takim przypadku jest to potencjalnie niebezpieczne. Dlatego jest tam ostrzeżenie.


16
Dziękujemy nie tylko za wspomnienie o SafeVarags, ale także za poinformowanie nas, kiedy możemy go użyć.
— KitsuneYMG

12
Jeśli nie było to od razu oczywiste dla nikogo (jak nie dla mnie), Javadocs dla @SafeVarargsma przykład metody, która jest niebezpieczna docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs .html
— michiakig

3
Więc @SafeVarargsmoże być używany, gdy twoja metoda zużywa tylko elementy tablicy i nie produkuje (i nigdy nie będzie) wytwarzać elementów do umieszczenia w tablicy? Należy zachować szczególną ostrożność, jeśli przypisujesz argument tablicowy do pola, którym można manipulować innymi metodami, ponieważ ustalenie, że nie są wykonywane na nim niebezpieczne operacje, może nie być trywialne.
— neXus

13

Ponieważ kompilator java używa niejawnego tworzenia tablicy dla varargs, a java nie zezwala na tworzenie ogólnej tablicy (ponieważ argument typu nie jest reifable).

Poniższy kod jest poprawny (te operacje są dozwolone w przypadku tablic), dlatego potrzebne jest niezaznaczone ostrzeżenie:

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

Zobacz obszerne wyjaśnienie tutaj

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.