Что такое SuppressWarnings (не отмечено) в Java?

Иногда, просматривая код, я вижу, что многие методы указывают аннотацию:

@SuppressWarnings("unchecked")

Что это значит?


person jojo    schedule 15.07.2009    source источник


Ответы (11)


Иногда дженерики Java просто не позволяют вам делать то, что вы хотите, и вам нужно эффективно сообщить компилятору, что то, что вы делаете, действительно будет законным во время выполнения.

Обычно я нахожу это неприятным, когда высмеиваю общий интерфейс, но есть и другие примеры. Обычно стоит попытаться найти способ избежать предупреждения, а не подавить его (Часто задаваемые вопросы по Java Generics здесь помогает), но иногда, даже если это возможно, он искажает форму кода настолько, что подавление предупреждения становится более аккуратным. В этом случае всегда добавляйте пояснительный комментарий!

В том же часто задаваемом типе часто задаваемых вопросов есть несколько разделов по этой теме, начиная с "Что такое" не отмечен "предупреждение?" - это стоит прочитать.

person Jon Skeet    schedule 15.07.2009
comment
В некоторых случаях этого можно избежать, используя YourClazz.class.cast (). Работает для контейнеров с одним универсальным элементом, но не для коллекций. - person akarnokd; 15.07.2009
comment
Или лучше использовать универсальные шаблоны (YourClazz<?>) - Java никогда не предупреждает о таких преобразованиях, поскольку они безопасны. Однако это не всегда срабатывает (подробности см. В часто задаваемых вопросах по обобщениям). - person Konrad Borowski; 21.01.2018

Это примечание для подавления предупреждений компиляции о непроверенных универсальных операциях (не исключениях), таких как приведение типов. По сути, это означает, что программист не хотел получать уведомления об этом, о чем он уже знает при компиляции определенного бита кода.

Вы можете прочитать больше об этой аннотации здесь:

SuppressWarnings

Кроме того, Oracle предоставляет здесь некоторую учебную документацию по использованию аннотаций:

Аннотации

Как они выразились,

«Предупреждение« непроверенное »может появиться при взаимодействии с унаследованным кодом, написанным до появления универсальных шаблонов (обсуждалось в уроке под названием Generics)».

person dreadwail    schedule 15.07.2009

Это также может означать, что текущая версия системы типов Java не подходит для вашего случая. Было несколько предложений JSR / хаков, чтобы исправить это: Введите токены, Токены супертипа, Class.cast ().

Если вам действительно нужно это подавление, сузьте его как можно больше (например, не помещайте его в сам класс или в длинный метод). Пример:

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

   Collections.reverse(list);
   return list;
}
person akarnokd    schedule 15.07.2009

Аннотация SuppressWarning используется для подавить предупреждения компилятора для аннотированного элемента. В частности, категория unchecked позволяет подавлять предупреждения компилятора, генерируемые в результате непроверенных приведений типов.

person Brandon E Taylor    schedule 15.07.2009
comment
Ваша ссылка SupressWarning не работает; вот альтернатива: docs.oracle.com/ javase / specs / jls / se6 / html / - person James Daily; 29.07.2015

Проще говоря: это предупреждение, которым компилятор указывает, что он не может гарантировать безопасность типов.

Метод обслуживания JPA, например:

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

Если бы я не аннотировал здесь @SuppressWarnings («unchecked»), у него была бы проблема со строкой, в которой я хочу вернуть свой ResultList.

В сокращенном виде означает безопасность типов: программа считается типобезопасной, если она компилируется без ошибок и предупреждений и не вызывает никаких неожиданных исключений ClassCastException во время выполнения.

Я использую http://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html < / а>

person Daniel Perník    schedule 07.02.2015
comment
Это хороший пример для ситуации, когда нам нужно использовать SuppressWarnings. - person Jimmy; 13.10.2015

В Java универсальные шаблоны реализованы посредством стирания типов. Например, следующий код.

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 не знает, какие общие типы используются при запуске программы, поэтому она компилируется и запускается, а для виртуальной машины Java это приведение к типу 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;
}

Это приведение безопасно, поскольку значение, хранящееся в пустом необязательном элементе, не может быть получено, поэтому нет риска неожиданных исключений приведения классов.

person Konrad Borowski    schedule 21.01.2018

Вы можете подавить предупреждения компилятора и сообщить дженерикам, что написанный вами код является законным в соответствии с ними.

Пример:

@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;
 }
person s.k.sumaprakash    schedule 09.09.2010

Один из приемов - создать интерфейс, расширяющий общий базовый интерфейс ...

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

Затем вы можете проверить это с помощью instanceof перед приведением ...

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;
person Brian Edwards    schedule 17.09.2010

Насколько мне известно, на данный момент это связано с подавлением предупреждений о дженериках; дженерики - это новая программная конструкция, не поддерживаемая в версиях JDK до JDK 5, поэтому любое смешение старых конструкций с новыми может привести к неожиданным результатам.

Компилятор предупреждает об этом программиста, но если программист уже знает, он может отключить эти ужасные предупреждения с помощью SuppressWarnings.

person BakerTheHacker    schedule 15.07.2009
comment
JDK5 новый? Он завершил большую часть своего срока службы. - person Tom Hawtin - tackline; 15.07.2009
comment
Я знаю, что JDK 5 довольно устарел, я имел в виду, что он новый в том смысле, что он представил новые функции для Java, ранее не предлагавшиеся в JDK 4. Также обратите внимание, что есть те, кто все еще ожидает JDK 7, прежде чем оставить JDK 5 позади. Я не могу понять почему, чтобы принять JDK 6! - person BakerTheHacker; 16.07.2009

Предупреждение, которым компилятор указывает, что он не может гарантировать безопасность типов. Термин «неконтролируемое» предупреждение вводит в заблуждение. Это не значит, что предупреждение каким-либо образом снято. Термин «непроверенный» относится к тому факту, что компилятор и исполняющая система не имеют достаточно информации о типе для выполнения всех проверок типов, которые были бы необходимы для обеспечения безопасности типов. В этом смысле некоторые операции «не отмечены».

Наиболее частый источник предупреждений о "непроверенных" предупреждениях - это использование необработанных типов. «непроверенные» предупреждения выдаются, когда к объекту обращаются через переменную необработанного типа, потому что необработанный тип не предоставляет достаточно информации о типе для выполнения всех необходимых проверок типа.

Пример (непроверенного предупреждения в сочетании с необработанными типами):

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

Когда вызывается метод add, компилятор не знает, безопасно ли добавлять объект String в коллекцию. Если TreeSet - это коллекция, содержащая String s (или ее супертип), тогда это будет безопасно. Но из информации о типе, предоставленной необработанным типом 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;

Приведение, целевой тип которого является параметризованным типом (конкретный или ограниченный подстановочный знак) или параметром типа, является небезопасным, если задействована проверка динамического типа во время выполнения. Во время выполнения доступно только стирание типа, а не точный статический тип, видимый в исходном коде. В результате часть выполнения приведения выполняется на основе стирания типа, а не на точном статическом типе.

В этом примере приведение к Wrapper будет проверять, является ли объект, возвращаемый из super.clone, оболочкой, а не оболочкой с определенным типом членов. Точно так же приведение к параметру типа T приводится к типу Object во время выполнения и, вероятно, полностью оптимизируется. Из-за стирания типа система времени выполнения не может выполнять более полезные проверки типов во время выполнения.

В некотором смысле исходный код вводит в заблуждение, потому что он предполагает, что выполняется приведение к соответствующему целевому типу, в то время как на самом деле динамическая часть приведения проверяет только стирание типа целевого типа. Предупреждение "непроверено" выдается, чтобы обратить внимание программиста на это несоответствие между статическим и динамическим аспектом приведения.

Обратитесь к: Что такое предупреждение о том, что флажок не установлен?

person Raghu K Nair    schedule 15.11.2018

Аннотация @SuppressWarnings - одна из трех встроенных аннотаций, доступных в JDK и добавленных вместе с @Override и @Deprecated в Java 1.5.

@SuppressWarnings предписывает компилятору игнорировать или подавлять указанное предупреждение компилятора в аннотированном элементе и всех программных элементах внутри этого элемента. Например, если класс аннотирован для подавления конкретного предупреждения, то предупреждение, созданное в методе внутри этого класса, также будет отделено.

Возможно, вы видели @SuppressWarnings («unchecked») и @SuppressWarnings («serial»), два самых популярных примера аннотации @SuppressWarnings. Бывший используется для подавления предупреждения, созданного из-за непроверенного приведения, в то время как более позднее предупреждение используется для напоминания о добавлении SerialVersionUID в класс Serializable.

Подробнее: https://javarevisited.blogspot.com/2015/09/what-is-suppresswarnings-annotation-in-java-unchecked-raw-serial.html#ixzz5rqQaOLUa

person Majid Roustaei    schedule 25.06.2019