Bagaimana cara saya perbaiki "Ekspresi daftar tipe perlu konversi yang tidak dicentang ... '?

137

Dalam cuplikan Java:

SyndFeedInput fr = new SyndFeedInput();
SyndFeed sf = fr.build(new XmlReader(myInputStream));
List<SyndEntry> entries = sf.getEntries();

baris terakhir menghasilkan peringatan

"Ekspresi tipe Listperlu konversi yang tidak dicentang untuk menyesuaikan dengan List<SyndEntry>"

Apa cara yang tepat untuk memperbaikinya?

pengguna46277
sumber

Jawaban:

96

Karena getEntriesmengembalikan mentah List, itu bisa menampung apa saja.

Pendekatan bebas-peringatan adalah membuat yang baru List<SyndEntry>, lalu melemparkan setiap elemen sf.getEntries()hasilnya SyndEntrysebelum menambahkannya ke daftar baru Anda. Collections.checkedListtidak tidak melakukan pengecekan ini untuk Anda-meskipun akan mungkin untuk menerapkannya untuk melakukannya.

Dengan melakukan pemeran Anda sendiri di muka, Anda "mematuhi persyaratan garansi" dari generik Java: jika a ClassCastExceptiondinaikkan, itu akan dikaitkan dengan pemeran dalam kode sumber, bukan pemeran tak terlihat yang dimasukkan oleh kompiler.

erickson
sumber
9
Terima kasih - itu adalah wawasan yang menarik tentang "garansi" dan para pemain tak terlihat yang dilakukan oleh kompiler versus para pemain yang dilakukan secara eksplisit dalam kode saya sendiri.
user46277
1
Ya, nilai obat generik yang tidak diverifikasi agak terbatas, tetapi itu adalah satu hal yang diberikannya. Hanya untuk memperjelas, ini mengharuskan kode Anda dikompilasi tanpa jenis peringatan keamanan.
erickson
Hai erickson, saya setuju bahwa ini memang solusi terbaik. Periksa jawaban saya stackoverflow.com/questions/367626/… untuk versi umum dari solusi ini.
Bruno De Fraine
115

Ini adalah masalah umum ketika berhadapan dengan API 5 pra-Jawa. Untuk mengotomatiskan solusi dari erickson , Anda dapat membuat metode generik berikut:

public static <T> List<T> castList(Class<? extends T> clazz, Collection<?> c) {
    List<T> r = new ArrayList<T>(c.size());
    for(Object o: c)
      r.add(clazz.cast(o));
    return r;
}

Ini memungkinkan Anda untuk melakukan:

List<SyndEntry> entries = castList(SyndEntry.class, sf.getEntries());

Karena solusi ini memeriksa bahwa elemen-elemen tersebut memang memiliki tipe elemen yang benar dengan menggunakan gips, itu aman, dan tidak memerlukan SuppressWarnings.

Bruno De Fraine
sumber
5
Mengenai metode yang disarankan oleh Bruno, Bukankah ini akan merusak kinerja aplikasi ketika memiliki Daftar dengan banyak elemen ?. Jawa harus membuang masing-masing dari mereka.
will824
2
Jika Anda menginginkan jaminan, itulah biayanya. Apakah ada opsi lain yang lebih murah? Jelas, jika Anda memiliki kendali atas metode pengembalian koleksi mentah yang dipanggil, atau bahkan memanggil metode atau mengakses koleksi menggunakan pendekatan lazy-demand. Adakah yang mempertimbangkan seluruh koleksi setelah pemanggilan metode?
dan
28

Sepertinya SyndFeedtidak menggunakan obat generik.

Anda bisa memiliki pemain yang tidak aman dan penindasan peringatan:

@SuppressWarnings("unchecked")
List<SyndEntry> entries = (List<SyndEntry>) sf.getEntries();

atau hubungi Collections.checkedList - meskipun Anda masih harus menekan peringatan:

@SuppressWarnings("unchecked")
List<SyndEntry> entries = Collections.checkedList(sf.getEntries(), SyndEntry.class);
Jon Skeet
sumber
Karena mereka berdua menekan peringatan, ada untungnya satu atau yang lain, atau preferensi? Terima kasih! Juga: apakah pemeran diperlukan jika penindasan yang tidak dicentang ada di tempatnya?
Dan Rosenstark
3
@Yar: Ya, Collections.checkedListakan mencegah penambahan elemen non-SyndEntry nanti. Saya pribadi tidak checkedListbanyak menggunakan , tetapi saya juga tidak sering masuk ke dalam situasi pemeran yang tidak diperiksa ini ...
Jon Skeet
9

Apakah Anda menulis SyndFeed?

Apakah sf.getEntriesmengembalikan Daftar atau List<SyndEntry>? Dugaan saya adalah ia kembali Listdan mengubahnya untuk kembali List<SyndEntry>akan memperbaiki masalah.

Jika SyndFeedmerupakan bagian dari perpustakaan, saya pikir Anda tidak dapat menghapus peringatan tanpa menambahkan @SuppressWarning("unchecked")anotasi ke metode Anda.

Alex B
sumber
Anda juga dapat menambahkan pemeran eksplisit.
Uri
3
Para pemain hanya akan menghasilkan peringatan lain, karena kode ini bukan tipe safe.
erickson
SyndFeedberasal dari rometools.github.io/rome/ROMEReleases/ROME1.0Release.html . Masalahnya tampaknya diperbaiki di versi Roma yang lebih baru seperti yang ditemukan di mvnrepository.com/artifact/com.rometools/rome/1.9.0
daloonik
2

Jika Anda menggunakan Guava dan semua yang ingin Anda lakukan adalah beralih melalui nilai-nilai Anda:

for(SyndEntry entry: Iterables.filter(sf.getEntries(), SyndEntry.class){
  ...
}

Jika Anda membutuhkan Daftar aktual yang dapat Anda gunakan

List<SyndEntry> list = Lists.newArrayList(
    Iterables.filter(sf.getEntries(), SyndEntry.class));

atau

List<SyndEntry> list = ImmutableList.copyOf(
    Iterables.filter(sf.getEntries(), SyndEntry.class));
Joseph K. Strauss
sumber
1
SyndFeedInput fr = new SyndFeedInput();
SyndFeed sf = fr.build(new XmlReader(myInputStream));
List<?> entries = sf.getEntries();
Honglonglong
sumber
2
Bahkan jika kode yang disediakan di sini menyelesaikan masalah, saya mendorong Anda untuk menjelaskan secara singkat mengapa hal itu terjadi. Tolong jelaskan mengapa jawaban yang diposting memecahkan masalah.
sbrattla
1

Jika Anda melihat javadoc untuk kelas SyndFeed(saya kira Anda merujuk ke kelas com.sun.syndication.feed.synd.SyndFeed), metode getEntries () tidak kembali java.util.List<SyndEntry>, tetapi mengembalikan hanya java.util.List.

Jadi, Anda perlu pemeran eksplisit untuk ini.

Shyam
sumber
0

Jika Anda tidak ingin memasukkan @SuppressWarning ("tidak dicentang") pada setiap panggilan sf.getEntries (), Anda selalu dapat membuat pembungkus yang akan mengembalikan Daftar.

Lihat pertanyaan lain ini

Boune
sumber
0

Lebih mudah lagi

return new ArrayList<?>(getResultOfHibernateCallback(...))

DennisTemper
sumber
Maka Anda akan berurusan dengan casting yang tepat (casting ulang?) Pada waktu penggunaan untuk setiap elemen di ArrayList <?>.
ingyhere