Apakah mungkin untuk menyelesaikan peringatan kompiler "Array generik T dibuat untuk parameter varargs"?


153

Ini adalah versi sederhana dari kode yang dipermasalahkan, satu kelas generik menggunakan kelas lain dengan parameter tipe generik dan perlu meneruskan salah satu tipe generik ke metode dengan parameter varargs:

class Assembler<X, Y> {
    void assemble(X container, Y... args) { ... }
}

class Component<T> {
    void useAssembler(T something) {

        Assembler<String, T> assembler = new Assembler<String, T>();

        //generates warning:
        // Type safety : A generic array of T is
        // created for a varargs parameter
        assembler.assemble("hello", something);
    }

}

Apakah ada cara yang benar untuk meneruskan parameter generik ke metode varargs tanpa menemui peringatan ini?

Tentu saja seperti itu

assembler.assemble("hello", new T[] { something });

tidak berfungsi karena Anda tidak dapat membuat array generik.


3
Yang aneh. Sepertinya kompiler harus dapat memastikan keamanan tipe penuh di sini.
erickson

3
Entri terkait dalam Java Generics FAQ Angelika Langer: angelikalanger.com/GenericsFAQ/FAQSections/…
Flow

Jawaban:


88

Selain menambahkan @SuppressWarnings("unchecked"), saya rasa tidak.

Laporan bug ini memiliki lebih banyak informasi tetapi bermuara pada kompiler yang tidak menyukai array tipe generik.


3
Lupa menyebutkan saya ingin menghindari @SuppressWarnings ("tidak dicentang"). Laporan bug itu memberi saya sedikit harapan!
matt b

3
Seperti yang dikatakan Joshua Bloch di Java Efektif: "Jangan mencampur generik dan array."
Timmos

20
kemudian, secara tersirat: jangan gunakan Varargs dengan Generics! Benar ... keputusan untuk memetakan vararg ke Array dan bukan Collection akan terus menyengat java selamanya. Bagus, Tuan Gosling.
bernstein

57

Tom Hawtin menunjukkan ini dalam komentar, tetapi untuk lebih eksplisit: ya, Anda dapat menyelesaikan ini di situs deklarasi (daripada situs panggilan (berpotensi banyak)): beralih ke JDK7.

Seperti yang dapat Anda lihat di posting blog Joseph Darcy , latihan Project Coin untuk memilih beberapa peningkatan bahasa tambahan kecil untuk Java 7 menerima proposal Bob Lee untuk memungkinkan sesuatu seperti@SuppressWarnings("varargs") di sisi metode untuk membuat peringatan ini hilang dalam situasi di mana ia dikenal sebagai aman.

Ini telah diterapkan di OpenJDK dengan komit ini .

Ini mungkin atau mungkin tidak berguna untuk proyek Anda (banyak orang tidak akan senang beralih ke versi JVM pra-rilis yang tidak stabil!) Tetapi mungkin itu - atau mungkin seseorang yang menemukan pertanyaan ini nanti (setelah JDK7 keluar ) akan bermanfaat.


7
Fitur Project Coin yang disebutkan sekarang tersedia - lihat @SafeVarargs di Jawa 7.
George Hawkins

Alternatif E dalam proposal Bob sangat menarik.
Christopher Perry

Java 8 tampaknya menggunakan @SafeVarargs alih-alih @SuppressWarnings ("varargs")
Paul Wintz

17

Jika Anda mencari antarmuka tipe fasih, Anda bisa mencoba pola builder. Tidak sesingkat varargs tetapi jenisnya aman.

Metode statis yang diketik secara umum dapat menghilangkan beberapa pelat ketel saat menggunakan pembangun, sembari tetap mempertahankan keamanan jenisnya.

Pembangun

public class ArgBuilder<T> implements Iterable<T> {

    private final List<T> args = new ArrayList<T>();

    public ArgBuilder<T> and(T arg) {
        args.add(arg);
        return this;
    }

    @Override
    public Iterator<T> iterator() {
        return args.iterator();
    }

    public static <T> ArgBuilder<T> with(T firstArgument) {
        return new ArgBuilder<T>().and(firstArgument);
    }
}

Menggunakannya

import static com.example.ArgBuilder.*;

public class VarargsTest {

    public static void main(String[] args) {
        doSomething(new ArgBuilder<String>().and("foo").and("bar").and("baz"));
        // or
        doSomething(with("foo").and("bar").and("baz"));
    }

    static void doSomething(Iterable<String> args) {
        for (String arg : args) {
            System.out.println(arg);
        }
    }
}

1
Kekuatan komposisi. Saya suka ini lebih dari varargs, ini lebih ekspresif.
Christopher Perry

1
@ChristopherPerry Anda juga harus mempertimbangkan basis kode Anda juga. Yang mendasarinya Collection(dalam hal ini a ArrayList) dipaksakan kepada penelepon, sedangkan mereka mungkin tahu bahwa a LinkedListlebih tepat, atau array yang tidak dapat diubah itu sendiri (seperti varargs dari pertanyaan OP). Dalam kasus penggunaan khusus, ini mungkin tepat, tetapi hanya menunjukkan bahwa ini juga merupakan batasan, dengan cara, tergantung pada kode di sekitar ini dan kebutuhan Anda.
searchengine27

5

Pengecoran parameter secara eksplisit ke Object dalam pemanggilan metode vararg akan membuat kompiler senang tanpa beralih ke @SuppressWarnings.

public static <T> List<T> list( final T... items )
{
    return Arrays.asList( items );
}

// This will produce a warning.
list( "1", 2, new BigDecimal( "3.5" ) )

// This will not produce a warning.
list( (Object) "1", (Object) 2, (Object) new BigDecimal( "3.5" ) )

// This will not produce a warning either. Casting just the first parameter to 
// Object appears to be sufficient.
list( (Object) "1", 2, new BigDecimal( "3.5" ) )

Saya percaya masalah di sini adalah bahwa kompiler perlu mencari tahu apa jenis konkret array untuk dibuat. Jika metode ini tidak generik, kompiler dapat menggunakan informasi tipe dari metode. Jika metode ini generik, ia mencoba mencari tahu tipe array berdasarkan parameter yang digunakan saat doa. Jika tipe parameternya homogenik, tugas itu mudah. Jika mereka berbeda, kompiler mencoba menjadi terlalu pintar menurut saya dan membuat array generik tipe-serikat. Maka terasa wajib untuk memperingatkan Anda tentang hal itu. Solusi yang lebih sederhana adalah membuat Object [] ketika tipe tidak dapat dipersempit dengan lebih baik. Solusi di atas hanya memaksakan hal itu.

Untuk memahami ini lebih baik, bermain-main dengan doa ke metode daftar di atas dibandingkan dengan metode list2 berikut.

public static List<Object> list2( final Object... items )
{
    return Arrays.asList( items );
}

Ini berfungsi, juga misalnya: Iterator <?> It = Arrays.asList ((Object) t) .iterator; if (if, hasNext ()) {class = it.next (). getClass (); } misalnya untuk mendapatkan kelas dari objek dari array bertipe tidak dikenal.
ggb667

2

Anda dapat menambahkan @SafeVarargs ke metode sejak Java 7, dan Anda tidak perlu membuat catatan pada kode klien.

class Assembler<X, Y> {

    @SafeVarargs
    final void assemble(X container, Y... args) {
        //has to be final...
    }
}

1

Anda dapat memiliki kelebihan metode. Ini tidak menyelesaikan masalah Anda tetapi meminimalkan jumlah peringatan (dan ya, ini peretasan!)

class Assembler<X, Y> {
  void assemble(X container, Y a1) { ... }
  void assemble(X container, Y a1, Y a2) { ... }
  void assemble(X container, Y a1, Y a2, Y a3) { ... }
  void assemble(X container, Y a1, Y a2, Y a3, Y a4) { ... }
  void assemble(X container, Y... args) { ... }
}

23
Ew. Inilah jenis peretasan yang seharusnya dicegah oleh vararg.
Amanda S

1
Ini bisa menjadi pendekatan yang valid, misalnya, lihat Guava's ImmutableSet.of .
Jonathan

1

Ini adalah masalah yang sangat mudah untuk dipecahkan: Gunakan List<T>!

Susunan jenis referensi harus dihindari.

Dalam versi Java saat ini (1.7), Anda dapat menandai metode @SafeVargsyang akan menghapus peringatan dari pemanggil. Hati-hati dengan itu, dan Anda masih lebih baik tanpa array warisan.

Lihat juga Peringatan Kompiler yang Ditingkatkan dan Kesalahan Saat Menggunakan Parameter Formal yang Tidak Dapat Diperbaiki dengan catatan teknis Metode Varargs .


6
ini tidak bisa dihindari dengan parameter varargs, bukan?
matt b

4
Ada proposal untuk JDK7 untuk memungkinkan penindasan peringatan untuk pergi pada deklarasi metode varargs daripada penggunaannya.
Tom Hawtin - tackline

11
Ini sepenuhnya mengabaikan aspek penting dari pertanyaan penulis - parameter vararg DO membuat array, dan yang menghasilkan peringatan ini.
Daniel Yankowsky

2
Saya setuju dengan @Tom Hawtin - tackline. Untuk perinciannya, lihat Bloch << Effecive Java >> Item 25: Lebih suka daftar dari array.
Stan Kurilin

2
Saya biasanya setuju dengan Bloch untuk yang satu ini, tetapi varargs adalah pengecualian yang jelas untuk aturan ini ...
Joeri Hendrickx

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.