Java tidak dicentang: pembuatan larik umum tidak dicentang untuk parameter varargs

112

Saya telah mengatur Netbeans untuk menampilkan peringatan yang tidak dicentang dalam kode Java saya, tetapi saya gagal memahami kesalahan pada baris berikut:

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

Memberikan:

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

Sumber metode:

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

Apa sebenarnya yang salah dan bagaimana cara memperbaikinya, karena menurut saya meninggalkan peringatan yang tidak dicentang dalam kode bukanlah ide yang baik?

Lupa menyebutkan, tapi saya menggunakan Java 7.

Sunting : Saya juga melihat sekarang bahwa metode ini memiliki yang berikut:

[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
sumber
17
Apa pun yang Anda lakukan, di Java Anda tidak perlu menginisialisasi larik int yang baru dibuat dengan 0s ...
Thomas Mueller
1
@ThomasMueller Tangkapan yang bagus di sana
skiwi

Jawaban:

165

Seperti yang disebutkan janoh.janoh di atas, vararg di Java hanyalah gula sintaksis untuk larik ditambah dengan pembuatan larik implisit di situs pemanggil. Begitu

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

sebenarnya

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

Namun seperti yang Anda ketahui, new List<String>[]tidak diperbolehkan di Java, karena alasan yang telah dibahas dalam banyak pertanyaan lain, tetapi terutama berkaitan dengan fakta bahwa array mengetahui tipe komponennya saat runtime, dan memeriksa pada waktu proses apakah elemen yang ditambahkan cocok dengan komponennya. tipe, tapi pemeriksaan ini tidak mungkin untuk tipe berparameter.

Bagaimanapun, daripada gagal, kompilator tetap membuat larik. Itu melakukan sesuatu yang mirip dengan ini:

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

Ini berpotensi tidak aman, tetapi belum tentu tidak aman. Kebanyakan metode varargs hanya melakukan iterasi terhadap elemen varargs dan membacanya. Dalam kasus ini, itu tidak peduli dengan jenis runtime dari array. Ini kasusnya dengan metode Anda. Karena Anda menggunakan Java 7, Anda harus menambahkan @SafeVarargsanotasi ke metode Anda, dan Anda tidak akan mendapatkan peringatan ini lagi. Anotasi ini pada dasarnya mengatakan, metode ini hanya peduli pada jenis elemen, bukan jenis lariknya.

Namun, ada beberapa metode varargs yang menggunakan tipe runtime dari array. Dalam kasus ini, ini berpotensi tidak aman. Karena itulah peringatan itu ada.

newacct
sumber
16
Terima kasih tidak hanya menyebut SafeVarags, tapi juga memberi tahu kami kapan kami bisa menggunakannya.
KitsuneYMG
12
Jika tidak langsung terlihat oleh siapa pun (seperti tidak bagi saya), Javadocs untuk @SafeVarargsmemiliki contoh metode yang tidak aman docs.oracle.com/javase/7/docs/api/java/lang/SafeVarargs .html
michiakig
3
Jadi @SafeVarargsdapat digunakan ketika metode Anda hanya menggunakan elemen dari array dan tidak (dan tidak akan pernah) menghasilkan elemen untuk dimasukkan ke dalam array? Perhatian khusus harus diberikan jika Anda menetapkan argumen larik ke bidang yang mungkin dimanipulasi oleh metode lain karena menentukan bahwa tidak ada operasi tidak aman yang dilakukan pada bidang itu mungkin tidak sepele.
neXus
13

Karena kompilator java menggunakan pembuatan larik implisit untuk vararg, dan java tidak mengizinkan pembuatan larik generik (karena argumen tipe tidak dapat diubah).

Kode di bawah ini benar (operasi ini diperbolehkan dengan array), jadi diperlukan peringatan yang tidak dicentang:

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

Lihat penjelasan lengkapnya di sini

Philip Voronov
sumber