SuppressWarnings (không được kiểm tra) trong Java là gì?


443

Thỉnh thoảng khi xem qua mã, tôi thấy nhiều phương thức chỉ định một chú thích:

@SuppressWarnings("unchecked")

Điều đó có nghĩa là gì?

Câu trả lời:


420

Đôi khi, các tổng quát Java không cho phép bạn làm những gì bạn muốn và bạn cần nói với trình biên dịch một cách hiệu quả rằng những gì bạn đang làm thực sự sẽ hợp pháp tại thời điểm thực thi.

Tôi thường thấy đây là một nỗi đau khi tôi chế giễu một giao diện chung, nhưng cũng có những ví dụ khác. Nó thường giá trị cố gắng để tìm ra một cách để tránh các cảnh báo chứ không phải là đàn áp nó ( Java Generics FAQ giúp ở đây) nhưng đôi khi ngay cả khi nó có thể, nó uốn cong mã ra khỏi hình dạng đến nỗi ức chế cảnh báo là gọn gàng. Luôn luôn thêm một nhận xét giải thích trong trường hợp đó!

Câu hỏi thường gặp chung chung có một số phần về chủ đề này, bắt đầu bằng "Cảnh báo" không được kiểm tra "là gì?" - nó cũng đáng để đọc.


10
Trong một số trường hợp, bạn có thể tránh nó bằng cách sử dụng YourClazz. Class.cast (). Hoạt động cho các thùng chứa phần tử chung duy nhất nhưng không cho các bộ sưu tập.
akarnokd

Hoặc tốt nhất là sử dụng các ký tự đại diện (YourClazz<?>)- Java không bao giờ cảnh báo về các phôi như vậy vì chúng an toàn. Điều này sẽ không luôn luôn hoạt động (xem Câu hỏi thường gặp về chi tiết).
Konrad Borowski

48

Đây là một chú thích để ngăn chặn các cảnh báo biên dịch về các hoạt động chung không được kiểm soát (không phải ngoại lệ), chẳng hạn như phôi. Về cơ bản nó ngụ ý rằng lập trình viên không muốn được thông báo về những điều mà anh ta đã biết khi biên dịch một đoạn mã cụ thể.

Bạn có thể đọc thêm về chú thích cụ thể này ở đây:

SuppressWarnings

Ngoài ra, Oracle cung cấp một số tài liệu hướng dẫn về việc sử dụng các chú thích ở đây:

Chú thích

Khi họ đặt nó,

"Cảnh báo 'không được kiểm tra' có thể xảy ra khi giao tiếp với mã kế thừa được viết trước khi xuất hiện thuốc generic (được thảo luận trong bài học có tiêu đề Generics)."


19

Điều đó cũng có nghĩa là phiên bản hệ thống kiểu Java hiện tại không đủ tốt cho trường hợp của bạn. Có một số đề xuất / hack của JSR để sửa lỗi này: Loại mã thông báo, Mã thông báo siêu loại , Class.cast ().

Nếu bạn thực sự cần sự giảm áp này, hãy thu hẹp nó càng nhiều càng tốt (ví dụ: không đặt nó lên chính lớp hoặc vào một phương thức dài). Một ví dụ:

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

   Collections.reverse(list);
   return list;
}

10

Các SuppressWarning chú thích được sử dụng để cảnh báo trình biên dịch đàn áp đối với các yếu tố được chú thích. Cụ thể, uncheckeddanh mục cho phép triệt tiêu các cảnh báo của trình biên dịch được tạo do kết quả của các kiểu phôi không được kiểm tra.


Liên kết SupressWarning của bạn đã chết; đây là một giải pháp thay thế: docs.oracle.com/javase/specs/jls/se6/html/ mẹo
James Daily

8

Đơn giản: Đó là một cảnh báo mà trình biên dịch chỉ ra rằng nó không thể đảm bảo an toàn kiểu.

Phương pháp dịch vụ JPA chẳng hạn:

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

Nếu tôi không anotate @SuppressWarnings ("không được kiểm tra") ở đây, nó sẽ có vấn đề với dòng, nơi tôi muốn trả về Danh sách kết quả của mình.

Trong các phím tắt có nghĩa là an toàn loại: Một chương trình được coi là an toàn kiểu nếu nó biên dịch không có lỗi và cảnh báo và không đưa ra bất kỳ ClassCastException bất ngờ nào trong thời gian chạy.

Tôi xây dựng trên http://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html


2
Đây là một ví dụ tốt cho tình huống chúng ta cần sử dụng SuppressWarnings.
Jimmy

8

Trong Java, generic được thực hiện bằng phương pháp xóa kiểu. Ví dụ, mã sau đây.

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

Được biên soạn như sau.

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

List.ofđược định nghĩa là.

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

Mà sau khi loại tẩy xóa trở thành.

static List of(Object e1, Object e2);

Trình biên dịch không có ý tưởng gì về các loại chung trong thời gian chạy, vì vậy nếu bạn viết một cái gì đó như thế này.

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

Máy ảo Java không biết các loại chung là gì khi chạy chương trình, do đó, nó biên dịch và chạy, như đối với Máy ảo Java, đây là Listkiểu truyền (đây là điều duy nhất nó có thể xác minh, vì vậy nó chỉ xác minh điều đó).

Nhưng bây giờ thêm dòng này.

Integer hello = actualList.get(0);

Và JVM sẽ đưa ra một điều bất ngờ ClassCastException, khi trình biên dịch Java chèn một ép kiểu ngầm định.

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

Một uncheckedcảnh báo cho một lập trình viên rằng một diễn viên có thể khiến chương trình ném ngoại lệ vào một nơi khác. Việc ngăn chặn cảnh báo bằng cách báo @SuppressWarnings("unchecked")cho trình biên dịch rằng lập trình viên tin rằng mã này an toàn và sẽ không gây ra ngoại lệ bất ngờ.

Tại sao bạn muốn làm điều đó? Hệ thống kiểu Java không đủ tốt để thể hiện tất cả các kiểu sử dụng kiểu có thể. Đôi khi bạn có thể biết rằng diễn viên là an toàn, nhưng Java không cung cấp cách nói như vậy - để ẩn các cảnh báo như thế này, @SupressWarnings("unchecked")có thể được sử dụng, để lập trình viên có thể tập trung vào các cảnh báo thực. Chẳng hạn, Optional.empty()trả về một singleton để tránh phân bổ các tùy chọn trống không lưu trữ giá trị.

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

Truyền này là an toàn, vì giá trị được lưu trữ trong một tùy chọn trống không thể được truy xuất do đó không có rủi ro về ngoại lệ của lớp không mong muốn.


5

Bạn có thể loại bỏ các cảnh báo của trình biên dịch và nói với các tổng quát rằng mã mà bạn đã viết là hợp pháp theo nó.

Thí dụ:

@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

Một mẹo nhỏ là tạo một giao diện mở rộng giao diện cơ bản chung ...

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

Sau đó, bạn có thể kiểm tra nó với thể hiện trước khi diễn viên ...

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

Theo tôi biết, bây giờ nó phải làm với việc đàn áp những cảnh báo về thuốc generic; Generics là một cấu trúc lập trình mới không được hỗ trợ trong các phiên bản JDK sớm hơn JDK 5, do đó, bất kỳ sự pha trộn nào của các cấu trúc cũ với các cấu trúc mới có thể gây ra một số kết quả không mong muốn.

Trình biên dịch cảnh báo cho lập trình viên về nó, nhưng nếu lập trình viên đã biết, họ có thể tắt những cảnh báo đáng sợ đó bằng SuppressWarnings.


1
JDK5 có mới không? Nó đã hoàn thành phần lớn thời gian kết thúc thời gian phục vụ.
Tom Hawtin - tackline

Tôi biết rằng JDK 5 khá lỗi thời, ý tôi là, nó mới theo nghĩa là nó đã giới thiệu các tính năng mới cho Java, trước đây không được cung cấp trong JDK 4. Cũng lưu ý rằng có những người vẫn đang chờ đợi JDK 7 trước khi bỏ lại JDK 5 để nắm lấy JDK 6, tôi không thể hiểu tại sao!
BakerTheHacker

2

Một cảnh báo mà trình biên dịch chỉ ra rằng nó không thể đảm bảo an toàn kiểu. Thuật ngữ "không được kiểm tra" là sai lệch. Điều đó không có nghĩa là cảnh báo không được kiểm tra theo bất kỳ cách nào. Thuật ngữ "không được kiểm tra" đề cập đến thực tế là trình biên dịch và hệ thống thời gian chạy không có đủ thông tin loại để thực hiện tất cả các kiểm tra loại cần thiết để đảm bảo an toàn loại. Theo nghĩa này, các hoạt động nhất định là "không được kiểm soát".

Nguồn cảnh báo "không được kiểm soát" phổ biến nhất là việc sử dụng các loại thô. Các cảnh báo "không được kiểm tra" được đưa ra khi một đối tượng được truy cập thông qua biến kiểu thô, bởi vì kiểu thô không cung cấp đủ thông tin loại để thực hiện tất cả các kiểm tra loại cần thiết.

Ví dụ (cảnh báo không được kiểm tra kết hợp với các loại thô):

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

Khi phương thức add được gọi, trình biên dịch không biết liệu có an toàn không khi thêm đối tượng String vào bộ sưu tập. Nếu TreeSet là một bộ sưu tập có chứa String s (hoặc siêu kiểu của chúng), thì nó sẽ an toàn. Nhưng từ thông tin loại được cung cấp bởi loại Rawset, trình biên dịch không thể biết được. Do đó, cuộc gọi có khả năng không an toàn và cảnh báo "không được kiểm tra" được đưa ra.

Các cảnh báo "không được kiểm tra" cũng được báo cáo khi trình biên dịch tìm thấy một nhóm có loại mục tiêu là loại tham số hoặc loại tham số.

Ví dụ (về một cảnh báo không được kiểm tra kết hợp với chuyển sang kiểu hoặc tham số biến tham số):

  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;

Một kiểu đúc có loại mục tiêu là loại tham số (cụ thể hoặc ký tự đại diện) hoặc tham số loại không an toàn, nếu có kiểm tra loại động khi chạy. Trong thời gian chạy, chỉ có loại xóa có sẵn, không phải là loại tĩnh chính xác có thể nhìn thấy trong mã nguồn. Kết quả là, phần thời gian chạy của dàn diễn viên được thực hiện dựa trên kiểu xóa chứ không phải kiểu tĩnh chính xác.

Trong ví dụ, cast to Wrapper sẽ kiểm tra xem đối tượng được trả về từ super.clone có phải là Wrapper không, liệu nó có phải là một Wrapper với một loại thành viên cụ thể không. Tương tự, các phôi cho tham số loại T được truyền sang loại Object khi chạy và có thể được tối ưu hóa hoàn toàn. Do xóa kiểu, hệ thống thời gian chạy không thể thực hiện kiểm tra loại hữu ích hơn khi chạy.

Theo một cách nào đó, mã nguồn bị sai lệch, bởi vì nó gợi ý rằng việc truyền vào loại mục tiêu tương ứng được thực hiện, trong khi trên thực tế, phần động của vật đúc chỉ kiểm tra chống lại loại xóa của loại mục tiêu. Cảnh báo "không được kiểm tra" được đưa ra để thu hút sự chú ý của lập trình viên về sự không phù hợp này giữa khía cạnh tĩnh và động của diễn viên.

Vui lòng tham khảo: Cảnh báo "không được kiểm tra" là gì?


2

Chú thích @SuppressWarnings là một trong ba chú thích tích hợp có sẵn trong JDK và được thêm vào cùng với @Override và @Deprecated trong Java 1.5.

@SuppressWarnings hướng dẫn trình biên dịch bỏ qua hoặc triệt tiêu, cảnh báo trình biên dịch đã chỉ định trong phần tử chú thích và tất cả các phần tử chương trình bên trong phần tử đó. Ví dụ: nếu một lớp được chú thích để chặn một cảnh báo cụ thể, thì một cảnh báo được tạo trong một phương thức bên trong lớp đó cũng sẽ được tách ra.

Bạn có thể đã thấy @SuppressWarnings ("không được kiểm tra") và @SuppressWarnings ("nối tiếp"), hai ví dụ phổ biến nhất của chú thích @SuppressWarnings. Trước đây được sử dụng để chặn cảnh báo được tạo do truyền không được kiểm tra trong khi cảnh báo sau được sử dụng để nhắc nhở về việc thêm serialVersionUID trong lớp Nối tiếp.

Đọc thêm: https://javarevisited.blogspot.com/2015/09/what-is-suppresswarnings-annotation-in-java-unchecked-raw-serial.html#ixzz5rqQaOLUa

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.