Apa itu SuppressWarnings ("tidak dicentang") di Jawa?

443

Kadang ketika melihat-lihat kode, saya melihat banyak metode menentukan anotasi:

@SuppressWarnings("unchecked")

Apa artinya ini?

jojo
sumber

Jawaban:

420

Kadang-kadang Java generik hanya tidak membiarkan Anda melakukan apa yang ingin Anda, dan Anda perlu untuk secara efektif memberitahu compiler bahwa apa yang Anda lakukan benar-benar akan menjadi hukum pada waktu eksekusi.

Saya biasanya menemukan ini menyakitkan ketika saya mengejek antarmuka generik, tetapi ada contoh lain juga. Ini biasanya layak mencoba untuk bekerja keluar cara menghindari peringatan daripada menekan itu ( Java Generik FAQ membantu di sini) tapi kadang-kadang bahkan jika ini mungkin, membungkuk kode keluar dari bentuk sehingga menekan peringatan adalah lebih rapi. Selalu tambahkan komentar jelas dalam kasus itu!

FAQ generik yang sama memiliki beberapa bagian pada topik ini, dimulai dengan "Apa itu peringatan" tidak dicentang "?" - Layak dibaca.

Jon Skeet
sumber
10
Dalam beberapa kasus, Anda dapat menghindarinya dengan menggunakan YourClazz.class.cast (). Bekerja untuk wadah elemen generik tunggal tetapi tidak untuk koleksi.
akarnokd
Atau lebih baik menggunakan generik wildcard (YourClazz<?>)- Java tidak pernah memperingatkan tentang gips karena aman. Ini tidak akan selalu berhasil (lihat FAQ generik untuk detailnya).
Konrad Borowski
48

Ini adalah anotasi untuk menekan kompilasi peringatan tentang operasi generik yang tidak diperiksa (bukan pengecualian), seperti gips. Ini pada dasarnya menyiratkan bahwa programmer tidak ingin diberitahu tentang ini yang dia sudah sadari ketika mengkompilasi sedikit kode tertentu.

Anda dapat membaca lebih lanjut tentang anotasi khusus ini di sini:

SuppressWarnings

Selain itu, Oracle menyediakan beberapa dokumentasi tutorial tentang penggunaan anotasi di sini:

Anotasi

Seperti yang mereka katakan,

"Peringatan 'tidak dicentang' dapat terjadi ketika berinteraksi dengan kode lama yang ditulis sebelum munculnya obat generik (dibahas dalam pelajaran berjudul Generics)."

rambut gimbal
sumber
19

Ini juga bisa berarti bahwa versi sistem tipe Java saat ini tidak cukup baik untuk kasus Anda. Ada beberapa proposisi / peretasan JSR untuk memperbaikinya: Ketik token, Token Super , Class.cast ().

Jika Anda benar-benar membutuhkan penindasan ini, persempit sebanyak mungkin (mis. Jangan menaruhnya di kelas itu sendiri atau ke metode yang panjang). Sebuah contoh:

public List<String> getALegacyListReversed() {
   @SuppressWarnings("unchecked") List<String> list =
       (List<String>)legacyLibrary.getStringList();

   Collections.reverse(list);
   return list;
}
akarnokd
sumber
10

The SuppressWarning penjelasan digunakan untuk peringatan compiler menekan untuk elemen dijelaskan. Secara khusus, uncheckedkategori ini memungkinkan penindasan peringatan kompiler yang dihasilkan sebagai hasil dari pemeran tipe yang tidak dicentang.

Brandon E Taylor
sumber
Tautan SupressWarning Anda sudah mati; inilah alternatifnya: docs.oracle.com/javase/specs/jls/se6/html/…
James Daily
8

Secara sederhana: Ini adalah peringatan dimana kompiler menunjukkan bahwa ia tidak dapat memastikan keamanan tipe.

Metode layanan JPA misalnya:

@SuppressWarnings("unchecked")
public List<User> findAllUsers(){
    Query query = entitymanager.createQuery("SELECT u FROM User u");
    return (List<User>)query.getResultList();
}

Jika saya tidak membuat anotasi @SuppressWarnings ("tidak dicentang") di sini, itu akan memiliki masalah dengan baris, di mana saya ingin mengembalikan Daftar Hasil saya.

Dalam cara pintas ketik-safety berarti: Suatu program dianggap aman-tipe jika ia dikompilasi tanpa kesalahan dan peringatan dan tidak memunculkan ClassCastException yang tidak terduga saat runtime.

Saya membangun di http://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html

Daniel Perník
sumber
2
Ini adalah contoh yang bagus untuk situasi di mana kita perlu menggunakan SuppressWarnings.
Jimmy
8

Di Jawa, obat generik diimplementasikan dengan cara penghapusan tipe. Misalnya, kode berikut.

List<String> hello = List.of("a", "b");
String example = hello.get(0);

Dikompilasi sebagai berikut.

List hello = List.of("a", "b");
String example = (String) hello.get(0);

Dan List.ofdidefinisikan sebagai.

static <E> List<E> of(E e1, E e2);

Yang setelah penghapusan tipe menjadi.

static List of(Object e1, Object e2);

Kompiler tidak tahu apa jenis generik saat runtime, jadi jika Anda menulis sesuatu seperti ini.

Object list = List.of("a", "b");
List<Integer> actualList = (List<Integer>) list;

Java Virtual Machine tidak tahu jenis generik apa saat menjalankan suatu program, jadi ini mengkompilasi dan berjalan, seperti untuk Java Virtual Machine, ini adalah pemeran untuk Listmengetik (ini adalah satu-satunya hal yang dapat diverifikasi, sehingga hanya memverifikasi itu).

Tapi sekarang tambahkan baris ini.

Integer hello = actualList.get(0);

Dan JVM akan melempar yang tidak terduga ClassCastException, ketika kompiler Java memasukkan pemeran implisit.

java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer

Sebuah uncheckedperingatan memberitahu seorang programmer yang gips dapat menyebabkan program untuk membuang pengecualian di tempat lain. Menekan peringatan dengan @SuppressWarnings("unchecked")memberi tahu kompiler bahwa programmer percaya kode aman dan tidak akan menyebabkan pengecualian yang tidak terduga.

Mengapa Anda ingin melakukan itu? Sistem tipe Java tidak cukup baik untuk mewakili semua pola penggunaan tipe yang mungkin. Terkadang Anda mungkin tahu bahwa para pemain aman, tetapi Java tidak menyediakan cara untuk mengatakannya - untuk menyembunyikan peringatan seperti ini, @SupressWarnings("unchecked")dapat digunakan, sehingga seorang programmer dapat fokus pada peringatan yang sebenarnya. Misalnya, Optional.empty()mengembalikan tunggal untuk menghindari alokasi opsional kosong yang tidak menyimpan nilai.

private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

Pemain ini aman, karena nilai yang disimpan dalam opsional kosong tidak dapat diambil sehingga tidak ada risiko pengecualian pemain kelas yang tidak terduga.

Konrad Borowski
sumber
5

Anda bisa menekan peringatan kompiler dan memberi tahu para generik bahwa kode yang Anda tulis itu legal menurutnya.

Contoh:

@SuppressWarnings("unchecked")
public List<ReservationMealPlan> retreiveMealPlan() {
     List<ReservationMealPlan> list=new ArrayList<ReservationMealPlan>();
    TestMenuService testMenuService=new TestMenuService(em, this.selectedInstance);
    list = testMenuService.getMeal(reservationMealPlan);
    return list;
 }
sksumaprakash
sumber
5

Salah satu triknya adalah membuat antarmuka yang memperluas antarmuka basis generik ...

public interface LoadFutures extends Map<UUID, Future<LoadResult>> {}

Kemudian Anda dapat memeriksanya dengan instanceof sebelum ...

Object obj = context.getAttribute(FUTURES);
if (!(obj instanceof LoadFutures)) {
    String format = "Servlet context attribute \"%s\" is not of type "
            + "LoadFutures. Its type is %s.";
    String msg = String.format(format, FUTURES, obj.getClass());
    throw new RuntimeException(msg);
}
return (LoadFutures) obj;
Brian Edwards
sumber
4

Sejauh yang saya tahu, untuk saat ini ada hubungannya dengan menekan peringatan tentang obat generik; generik adalah konstruk pemrograman baru yang tidak didukung dalam versi JDK lebih awal dari JDK 5, jadi campuran apa pun dari konstruksi lama dengan yang baru dapat menimbulkan beberapa hasil yang tidak terduga.

Compiler memperingatkan programmer tentang hal itu, tetapi jika programmer sudah tahu, mereka dapat mematikan peringatan yang ditakuti menggunakan SuppressWarnings.

BakerTheHacker
sumber
1
JDK5 baru? Ini telah menyelesaikan sebagian besar akhir Masa Layanannya.
Tom Hawtin - tackline
Saya tahu bahwa JDK 5 agak ketinggalan jaman, yang saya maksud adalah, itu baru dalam arti memperkenalkan fitur-fitur baru ke Java, yang sebelumnya tidak ditawarkan di JDK 4. Juga perhatikan bahwa masih ada yang menunggu JDK 7 sebelum meninggalkan JDK 5 untuk merangkul JDK 6, saya tidak bisa alasan mengapa!
BakerTheHacker
2

Peringatan dimana kompiler menunjukkan bahwa ia tidak dapat memastikan keamanan tipe. Istilah "tidak dicentang" peringatan itu menyesatkan. Itu tidak berarti bahwa peringatan itu tidak dicentang dengan cara apa pun. Istilah "tidak dicentang" mengacu pada fakta bahwa kompiler dan sistem runtime tidak memiliki informasi tipe yang cukup untuk melakukan semua pemeriksaan tipe yang diperlukan untuk memastikan keamanan tipe. Dalam pengertian ini, operasi tertentu "tidak dicentang".

Sumber paling umum dari peringatan "tidak dicentang" adalah penggunaan tipe mentah. peringatan "tidak dicentang" dikeluarkan ketika suatu objek diakses melalui variabel tipe mentah, karena tipe mentah tidak menyediakan informasi tipe yang cukup untuk melakukan semua pemeriksaan tipe yang diperlukan.

Contoh (peringatan tidak dicentang bersama dengan jenis mentah):

TreeSet set = new TreeSet(); 
set.add("abc");        // unchecked warning 
set.remove("abc");
warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.TreeSet 
               set.add("abc");  
                      ^

Ketika metode add dipanggil, kompiler tidak tahu apakah aman untuk menambahkan objek String ke koleksi. Jika TreeSet adalah koleksi yang berisi String s (atau supertype daripadanya), maka itu akan aman. Tetapi dari informasi jenis yang disediakan oleh tipe mentah TreeSet, kompiler tidak dapat memberi tahu. Karenanya panggilan tersebut berpotensi tidak aman dan peringatan "tidak dicentang" dikeluarkan.

peringatan "tidak dicentang" juga dilaporkan ketika kompiler menemukan pemain yang tipe targetnya adalah tipe parameter atau tipe parameter.

Contoh (peringatan yang tidak dicentang bersama dengan gips ke tipe atau variabel tipe parameter):

  class Wrapper<T> { 
  private T wrapped ; 
  public Wrapper (T arg) {wrapped = arg;} 
  ... 
  public Wrapper <T> clone() { 
    Wrapper<T> clon = null; 
     try {  
       clon = (Wrapper<T>) super.clone(); // unchecked warning 
     } catch (CloneNotSupportedException e) {  
       throw new InternalError();  
     } 
     try {  
       Class<?> clzz = this.wrapped.getClass(); 
       Method   meth = clzz.getMethod("clone", new Class[0]); 
       Object   dupl = meth.invoke(this.wrapped, new Object[0]); 
       clon.wrapped = (T) dupl; // unchecked warning 
     } catch (Exception e) {} 
     return clon; 
  } 
} 
warning: [unchecked] unchecked cast 
found   : java.lang.Object 
required: Wrapper <T> 
                  clon = ( Wrapper <T>)super.clone();  
                                                ^ 
warning: [unchecked] unchecked cast 
found   : java.lang.Object 
required: T 
                  clon. wrapped = (T)dupl;

Pemain yang tipe targetnya adalah tipe parameter (beton atau wildcard) atau parameter tipe tidak aman, jika pemeriksaan tipe dinamis saat runtime terlibat. Saat runtime, hanya tipe erasure yang tersedia, bukan tipe statis persis yang terlihat dalam kode sumber. Akibatnya, bagian runtime dari gips dilakukan berdasarkan pada tipe erasure, bukan pada tipe statis yang tepat.

Dalam contoh tersebut, para pemain ke Wrapper akan memeriksa apakah objek yang kembali dari super.clone adalah Wrapper, bukan apakah itu adalah wrapper dengan tipe anggota tertentu. Demikian pula, gips ke parameter tipe T dilemparkan untuk mengetik Objek saat runtime, dan mungkin dioptimalkan sekaligus. Karena penghapusan tipe, sistem runtime tidak dapat melakukan pemeriksaan tipe yang lebih berguna saat runtime.

Di satu sisi, kode sumber menyesatkan, karena itu menunjukkan bahwa pemain untuk jenis target masing-masing dilakukan, sementara pada kenyataannya bagian dinamis pemain hanya memeriksa terhadap penghapusan jenis jenis target. Peringatan "tidak dicentang" dikeluarkan untuk menarik perhatian programmer ke ketidakcocokan antara aspek statis dan dinamis para pemain.

Silakan merujuk: Apa itu peringatan "tidak dicentang"?

Raghu K Nair
sumber
2

Anotasi @SuppressWarnings adalah salah satu dari tiga anotasi bawaan yang tersedia di JDK dan ditambahkan bersama @Override dan @Deprecated di Java 1.5.

@SuppressWarnings memerintahkan kompiler untuk mengabaikan atau menekan, peringatan kompiler yang ditentukan dalam elemen beranotasi dan semua elemen program di dalam elemen itu. Misalnya, jika kelas diberi penjelasan untuk menekan peringatan tertentu, maka peringatan yang dihasilkan dalam metode di dalam kelas itu juga akan dipisahkan.

Anda mungkin telah melihat @SuppressWarnings ("tidak dicentang") dan @SuppressWarnings ("serial"), dua contoh paling populer dari anotasi @SuppressWarnings. Mantan digunakan untuk menekan peringatan yang dihasilkan karena pengecoran tidak dicentang sementara peringatan kemudian digunakan untuk mengingatkan tentang menambahkan SerialVersionUID dalam kelas Serializable.

Baca selengkapnya: https://javarevisited.blogspot.com/2015/09/what-is-suppresswarnings-annotation-in-java-unchecked-raw-serial.html#ixzz5rqQaOLUa

Majid Roustaei
sumber