SuppressWarnings (“ ไม่ถูกตรวจสอบ”) ใน Java คืออะไร?


443

บางครั้งเมื่อดูรหัสฉันเห็นหลายวิธีระบุคำอธิบายประกอบ:

@SuppressWarnings("unchecked")

สิ่งนี้หมายความว่า?

คำตอบ:


420

บางครั้ง generics Java ก็ไม่ยอมให้คุณทำสิ่งที่คุณต้องการและคุณต้องบอกคอมไพเลอร์อย่างมีประสิทธิภาพว่าสิ่งที่คุณทำจริงๆจะถูกกฎหมายในเวลาดำเนินการ

ฉันมักจะพบว่าสิ่งนี้เจ็บปวดเมื่อฉันเยาะเย้ยอินเทอร์เฟซทั่วไป แต่ก็มีตัวอย่างอื่นด้วย โดยปกติแล้วการพยายามหลีกเลี่ยงคำเตือนมากกว่าการระงับ ( Java Generics FAQช่วยได้ที่นี่) แต่บางครั้งก็เป็นไปได้ แต่มันจะโค้งรหัสออกไปมากจนการยับยั้งคำเตือนนั้นเป็นสิ่งที่ไม่ควรทำ เพิ่มความคิดเห็นที่อธิบายในกรณีนั้นเสมอ!

คำถามที่พบบ่อย generics เดียวกันมีหลายส่วนในหัวข้อนี้เริ่มต้นด้วย"คำเตือน" ไม่ถูกตรวจสอบ "คืออะไร? - มันคุ้มค่าที่จะอ่าน


10
ในบางกรณีคุณสามารถหลีกเลี่ยงได้โดยใช้ YourClazz.class.cast () ใช้งานได้กับคอนเทนเนอร์องค์ประกอบทั่วไป แต่ไม่เหมาะสำหรับคอลเลกชัน
akarnokd

หรือควรใช้สัญลักษณ์ตัวแทน(YourClazz<?>)- Java ไม่เคยเตือนเกี่ยวกับการปลดเปลื้องเช่นที่ปลอดภัย อย่างไรก็ตามวิธีนี้ใช้ไม่ได้เสมอ (ดูคำถามที่พบบ่อยเกี่ยวกับข้อมูลทั่วไป)
Konrad Borowski

48

มันเป็นคำอธิบายประกอบที่จะระงับการรวบรวมคำเตือนเกี่ยวกับการดำเนินงานทั่วไปที่ไม่ได้ตรวจสอบ (ไม่ใช่ข้อยกเว้น) เช่นการปลดเปลื้อง มันก็หมายความว่าโปรแกรมเมอร์ไม่ต้องการที่จะได้รับการแจ้งเตือนเกี่ยวกับสิ่งเหล่านี้ซึ่งเขารู้อยู่แล้วเมื่อรวบรวมบิตของรหัส

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับคำอธิบายประกอบเฉพาะนี้ได้ที่นี่:

SuppressWarnings

นอกจากนี้ Oracle ยังมีเอกสารการสอนเกี่ยวกับการใช้คำอธิบายประกอบที่นี่:

คำอธิบายประกอบ

ตามที่พวกเขาวางไว้

"คำเตือน 'ไม่ถูกตรวจสอบ' สามารถเกิดขึ้นได้เมื่อเชื่อมต่อกับรหัสดั้งเดิมที่เขียนก่อนการกำเนิดของ generics (กล่าวถึงในบทเรียนเรื่อง Generics)"


19

อาจหมายความว่ารุ่นระบบ Java ปัจจุบันไม่ดีพอสำหรับกรณีของคุณ มีข้อเสนอ JSRหลายอย่าง/ การแฮ็กในการแก้ไข: โทเค็นประเภท, โทเค็นประเภทซูเปอร์ , Class.cast ()

หากคุณต้องการการปราบปรามนี้ จำกัด ให้แคบที่สุดเท่าที่จะเป็นไปได้ (เช่นอย่าวางไว้บนชั้นเรียนหรือลงบนวิธีที่ยาว) ตัวอย่าง:

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

   Collections.reverse(list);
   return list;
}

10

SuppressWarningคำอธิบายประกอบที่ใช้ในการคำเตือนคอมไพเลอร์ปราบองค์ประกอบข้อเขียน โดยเฉพาะuncheckedหมวดหมู่ที่ช่วยให้การปราบปรามของคำเตือนคอมไพเลอร์ที่สร้างขึ้นเป็นผลมาจากการปลดประเภทไม่ได้ตรวจสอบ


ลิงก์ SupressWarning ของคุณตาย นี่เป็นทางเลือก: docs.oracle.com/javase/specs/jls/se6/html/ …
James Daily

8

ง่ายๆ: มันเป็นคำเตือนที่คอมไพเลอร์ระบุว่าไม่สามารถรับประกันความปลอดภัยของประเภท

ตัวอย่างวิธีการบริการ JPA:

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

หากฉันไม่ได้ใส่เครื่องหมาย @SuppressWarnings ("ไม่ถูกตรวจสอบ") ที่นี่จะมีปัญหากับบรรทัดที่ฉันต้องการส่งคืน ResultList ของฉัน

ในทางลัดประเภทความปลอดภัยหมายถึง: โปรแกรมได้รับการพิจารณาว่าเป็นประเภทที่ปลอดภัยหากคอมไพล์โดยไม่มีข้อผิดพลาดและคำเตือนและจะไม่เพิ่ม ClassCastException ที่ไม่คาดคิดในขณะใช้งานจริง

ฉันสร้างบนhttp://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html


2
นี่เป็นตัวอย่างที่ดีสำหรับสถานการณ์ที่เราจำเป็นต้องใช้ SuppressWarnings
จิมมี่

8

ใน Java, generics จะดำเนินการโดยใช้วิธีการลบประเภท ตัวอย่างเช่นรหัสต่อไปนี้

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

จะถูกคอมไพล์ต่อไปนี้

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

และList.ofถูกกำหนดให้เป็น

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

ซึ่งหลังจากการลบประเภทกลายเป็น

static List of(Object e1, Object e2);

คอมไพเลอร์ไม่มีความคิดว่าประเภททั่วไปของรันไทม์คืออะไรดังนั้นถ้าคุณเขียนอะไรแบบนี้

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

Java Virtual Machine ไม่รู้ว่าประเภททั่วไปคืออะไรในขณะที่เรียกใช้โปรแกรมดังนั้นการคอมไพล์และรันสำหรับ Java Virtual Machine นี้เป็นการส่งแบบโยนList(เป็นสิ่งเดียวที่สามารถตรวจสอบได้ดังนั้นจึงตรวจสอบได้เท่านั้น)

แต่ตอนนี้เพิ่มบรรทัดนี้

Integer hello = actualList.get(0);

และ JVM จะขว้างสิ่งที่ไม่คาดคิดClassCastExceptionออกไปเนื่องจากคอมไพเลอร์ Java แทรกการส่งโดยนัย

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

uncheckedเตือนบอกโปรแกรมเมอร์ที่หล่ออาจทำให้โปรแกรมที่จะโยนข้อยกเว้นที่อื่น การยับยั้งคำเตือนด้วย@SuppressWarnings("unchecked")จะบอกคอมไพเลอร์ว่าโปรแกรมเมอร์เชื่อว่ารหัสนั้นปลอดภัยและจะไม่ทำให้เกิดข้อยกเว้นที่ไม่คาดคิด

ทำไมคุณต้องการทำเช่นนั้น? ระบบชนิด Java ไม่ดีพอที่จะแสดงรูปแบบการใช้งานที่เป็นไปได้ทั้งหมด บางครั้งคุณอาจรู้ว่านักแสดงมีความปลอดภัย แต่ Java ไม่ได้มีวิธีที่จะพูดเช่นนั้น - เพื่อซ่อนคำเตือนเช่นนี้@SupressWarnings("unchecked")สามารถนำมาใช้เพื่อให้โปรแกรมเมอร์สามารถมุ่งเน้นไปที่คำเตือนจริง ตัวอย่างเช่นOptional.empty()ส่งคืนซิงเกิลตันเพื่อหลีกเลี่ยงการจัดสรรอ็อพชั่นว่างที่ไม่เก็บค่า

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

การร่ายนี้มีความปลอดภัยเนื่องจากค่าที่เก็บไว้ในตัวเลือกที่ว่างเปล่าไม่สามารถเรียกคืนได้ดังนั้นจึงไม่มีความเสี่ยงที่จะเกิดข้อยกเว้นการส่งคลาสที่ไม่คาดคิด


5

คุณสามารถระงับคำเตือนของคอมไพเลอร์และแจ้งให้ generics ทราบว่ารหัสที่คุณเขียนนั้นถูกต้องตามกฎหมาย

ตัวอย่าง:

@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;
 }

5

เคล็ดลับอย่างหนึ่งคือการสร้างส่วนต่อประสานที่ขยายส่วนต่อประสานฐานทั่วไป

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

จากนั้นคุณสามารถตรวจสอบกับอินสแตนซ์ก่อนร ...

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;

4

เท่าที่ฉันรู้ตอนนี้มันเกี่ยวข้องกับการยับยั้งคำเตือนเกี่ยวกับยาชื่อสามัญ; generics เป็นโครงสร้างการเขียนโปรแกรมใหม่ที่ไม่รองรับใน JDK เวอร์ชันก่อนหน้า JDK 5 ดังนั้นการผสมผสานใด ๆ ของการสร้างเก่ากับใหม่อาจมีผลลัพธ์ที่ไม่คาดคิด

คอมไพเลอร์เตือนโปรแกรมเมอร์เกี่ยวกับมัน แต่ถ้าโปรแกรมเมอร์รู้อยู่แล้วพวกเขาสามารถปิดคำเตือนที่หวั่นเหล่านั้นได้โดยใช้ SuppressWarnings


1
ใหม่ JDK5? มันจบช่วงเวลาสิ้นสุดการใช้งานเกือบทั้งหมดแล้ว
Tom Hawtin - tackline

ฉันรู้ว่า JDK 5 ค่อนข้างล้าสมัยสิ่งที่ฉันหมายถึงคือมันเป็นสิ่งใหม่ในแง่ที่ว่ามันได้นำเสนอคุณสมบัติใหม่ให้กับ Java ซึ่งก่อนหน้านี้ไม่ได้นำเสนอใน JDK 4 นอกจากนี้โปรดทราบว่ามีผู้ที่ยังคงรอ JDK 7 อยู่ เพื่อที่จะโอบกอด JDK 6 ฉันไม่สามารถให้เหตุผลได้!
BakerTheHacker

2

คำเตือนที่คอมไพเลอร์ระบุว่าไม่สามารถรับรองความปลอดภัยได้ คำเตือน "ไม่ถูกตรวจสอบ" ทำให้เข้าใจผิด ไม่ได้หมายความว่าจะไม่มีการตรวจสอบคำเตือน แต่อย่างใด คำว่า "ไม่ถูกตรวจสอบ" หมายถึงความจริงที่ว่าคอมไพเลอร์และระบบรันไทม์มีข้อมูลประเภทไม่เพียงพอที่จะทำการตรวจสอบประเภททั้งหมดที่จำเป็นเพื่อความปลอดภัยของประเภท ในแง่นี้การดำเนินการบางอย่าง "ไม่ถูกตรวจสอบ"

แหล่งที่มาที่พบบ่อยที่สุดของคำเตือน "ไม่ถูกตรวจสอบ" คือการใช้ชนิดข้อมูลดิบ คำเตือน "ไม่ จำกัด " จะออกเมื่อมีการเข้าถึงวัตถุผ่านตัวแปรประเภท raw เนื่องจากประเภท raw ไม่ได้ให้ข้อมูลประเภทเพียงพอที่จะทำการตรวจสอบประเภทที่จำเป็นทั้งหมด

ตัวอย่าง (คำเตือนที่ไม่ถูกตรวจสอบพร้อมกับประเภท raw):

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

เมื่อมีการเรียกใช้วิธีการเพิ่มคอมไพเลอร์ไม่ทราบว่าปลอดภัยที่จะเพิ่มวัตถุ String ในคอลเลกชัน ถ้า TreeSet เป็นคอลเลกชันที่มี String s (หรือ supertype ของมัน) ดังนั้นมันจะปลอดภัย แต่จากข้อมูลประเภทที่มีให้โดย TreeSet ชนิดดิบที่คอมไพเลอร์ไม่สามารถบอกได้ ดังนั้นการโทรจึงอาจไม่ปลอดภัยและมีการออกคำเตือน "ไม่ถูกตรวจสอบ"

คำเตือน "ไม่ถูกตรวจสอบ" จะถูกรายงานเช่นกันเมื่อคอมไพเลอร์พบนักแสดงที่มีประเภทเป้าหมายเป็นประเภทที่กำหนดพารามิเตอร์หรือพารามิเตอร์ประเภท

ตัวอย่าง (ของคำเตือนที่ไม่ถูกตรวจสอบพร้อมกับการส่งไปยังชนิดพารามิเตอร์หรือชนิดตัวแปร):

  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;

นักแสดงที่มีประเภทเป้าหมายเป็นประเภทพารามิเตอร์ (คอนกรีตหรือสัญลักษณ์ตัวแทน) หรือพารามิเตอร์ประเภทไม่ปลอดภัยหากการตรวจสอบประเภทแบบไดนามิกที่รันไทม์ที่เกี่ยวข้อง ณ รันไทม์มีเพียงการลบประเภทเท่านั้นไม่ใช่ชนิดสแตติกที่แน่นอนที่มองเห็นได้ในซอร์สโค้ด ดังนั้นส่วนรันไทม์ของการส่งจะดำเนินการตามการลบประเภทไม่ใช่ประเภทคงที่ที่แน่นอน

ในตัวอย่าง cast to Wrapper จะตรวจสอบว่าวัตถุที่ส่งคืนจาก super.clone เป็น Wrapper หรือไม่ไม่ว่าจะเป็น wrapper ที่มีสมาชิกประเภทใดประเภทหนึ่ง ในทำนองเดียวกันการร่ายไปยังพารามิเตอร์ประเภท T ถูกส่งไปยังการพิมพ์ Object ที่รันไทม์และอาจปรับให้เหมาะสมโดยรวม เนื่องจากการลบประเภทระบบรันไทม์ไม่สามารถทำการตรวจสอบประเภทที่มีประโยชน์มากขึ้นได้ที่รันไทม์

ในทางที่เป็นรหัสที่มาทำให้เข้าใจผิดเพราะมันแสดงให้เห็นว่าการโยนไปยังประเภทเป้าหมายที่เกี่ยวข้องจะดำเนินการในขณะที่ในความเป็นจริงส่วนแบบไดนามิกของการโยนเพียงตรวจสอบกับการลบประเภทของประเภทเป้าหมาย คำเตือน "ไม่ถูกตรวจสอบ" ถูกใช้เพื่อดึงความสนใจของโปรแกรมเมอร์ไปยังความไม่ตรงกันนี้ระหว่างลักษณะคงที่และไดนามิกของการร่าย

โปรดอ้างอิง: คำเตือน "ไม่ถูกตรวจสอบ" คืออะไร


2

@SuppressWarnings คำอธิบายประกอบเป็นหนึ่งในสามของหมายเหตุประกอบในตัวที่มีอยู่ใน JDK และเพิ่มไว้ข้าง @Override และ @Deprecated ใน Java 1.5

@SuppressWarnings สั่งให้คอมไพเลอร์เพิกเฉยหรือระงับคำเตือนคอมไพเลอร์ที่ระบุในองค์ประกอบที่มีคำอธิบายประกอบและองค์ประกอบโปรแกรมทั้งหมดภายในองค์ประกอบนั้น ตัวอย่างเช่นหากคลาสมีการเพิ่มความคิดเห็นเพื่อระงับคำเตือนเฉพาะคำเตือนที่สร้างขึ้นในวิธีการภายในคลาสนั้นจะถูกแยกออกเช่นกัน

คุณอาจเห็น @SuppressWarnings ("ไม่ จำกัด ") และ @SuppressWarnings ("serial") สองตัวอย่างยอดนิยมของการเพิ่มความคิดเห็น @SuppressWarnings อดีตถูกนำมาใช้เพื่อระงับการเตือนที่สร้างขึ้นเนื่องจากการคัดเลือกนักแสดงที่ไม่ได้ตรวจสอบในขณะที่การเตือนในภายหลังจะใช้เพื่อเตือนเกี่ยวกับการเพิ่ม SerialVersionUID ในชั้นเรียนแบบอนุกรม

อ่านเพิ่มเติม: https://javarevisited.blogspot.com/2015/09/what-is-suppresswarnings-annotation-in-java-unchecked-raw-serial.html#ixzz5rqQaOLUa

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.