Почему бы просто не отключить непроверенные предупреждения?

Когда разработчики взаимодействуют с нестандартными API, они обычно запускаются в "непроверенные" предупреждения. Рассмотрим следующий пример:

import java.util.AbstractList;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class IterableNodeList<T extends Node> extends AbstractList<T>
{
    private NodeList list;

    public IterableNodeList(NodeList list)
    {
        this.list = list;
    }

    public T get(int index)
    {
        return (T)this.list.item(index);
    }

    public int size()
    {
        return this.list.getLength();
    }
}

Можно было бы, конечно, приложить усилия, чтобы написать это так, чтобы не было предупреждения: используя параметр типа T в классе и аргумент конструктора Class<T>, сопоставляя переменную-член и вызов cast().

В качестве альтернативы можно было бы просто просто отредактировать конфигурацию IDE и создать скрипты (например, Maven POM), чтобы полностью отключить это предупреждение компилятора. Теперь, если бы мы это сделали, код мог остаться таким, каким он есть, но я уверен, что у этого дела должны быть недостатки. Однако я не могу представить никаких разумных, реалистичных примеров, где

  • это предупреждение дает больше значения, чем "наклеить на @SuppressWarnings здесь, нет никакой другой опции в любом случае" и где
  • полученный код действительно ведет себя по-другому (и безопаснее), чем тот, где мы игнорировали (отключили) предупреждение.

Можете ли вы придумать такие примеры или назвать еще одну причину, по которой отключение этих "непроверенных" предупреждений во всем мире - плохая идея? Или это на самом деле хорошая идея?

UPDATE

Предыдущие примеры фактически не вызывали предупреждения. Некоторые ответы уже не имеют смысла. Извините за неудобства.

Ответ 1

В соответствии с Item 24 of Effective Java 2nd Edition широкое и частое использование @SupressWarnings обычно плохое, особенно если вы применяете эту аннотацию ко всему классу, потому что такие предупреждения показывают вам, возможно, опасные фрагменты кода, которые могли бы привести к ClassCastException.

Но в некоторых случаях это может быть полезно, например, в реализации метода ArrayList toArray:

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

Ответ 2

Второй пример не приводит к предупреждению компилятора в моем затмении, и я не могу думать о причине, по которой это должно произойти. Поэтому это мое предпочтительное решение.

Причина, по которой существуют непроверенные предупреждения, заключается в том, что игнорирование их может привести к загрязнению кучи:

Проверяются обычные касты, т.е. они приводят к ClassCastException, если значение несовместимо с желаемым типом. Непроверенные броски не гарантируют этого, т.е. Могут преуспеть, даже если значение не соответствует типу. Это может привести к переменной, содержащей значение, которое не является подтипом его объявленного типа, условие Java spec вызывает "загрязнение кучи". Чтобы обеспечить целостность системы типа времени выполнения, компилятор Java будет вставлять обычные приведения, когда используется переменная типа общего типа. При наличии загрязнения кучи эти отливки могут выйти из строя.

Например, программа:

static void appendTo(List list) {
    list.add(1); // unchecked warning
}

static void printLengths(List<String> strings) {
    for (String s : strings) { // throws ClassCastException
        System.out.println(s.length());
    }
}

public static void main(String[] args) throws Exception {
    List<String> strings = new ArrayList<>();
    strings.add("hello");
    appendTo(strings);
    printLengths(strings);
}

выбрасывает ClassCastException в строке, которая не содержит листинг в исходном коде. Вероятно, это сильно смутит большинство программистов.

Вот почему я рекомендую использовать проверенные приведения, когда это возможно, либо с помощью не-общего набора, либо (в общем коде) отражающего литья:

class Habitat<T> {
    private final Class<T> clazz;

    private List<T> inhabitants;

    void add(Object o) {
        inhabitants.add(clazz.cast(o));
    }
}

Ответ 3

Из эффективного Java 2nd Edition:

Аннотация SuppressWarnings может использоваться при любой детализации из объявление отдельной локальной переменной для всего класса. Всегда используйте аннотацию SuppressWarnings на минимальной возможной области. Обычно это будет объявление переменной или очень короткий метод или конструктор. Никогда не используйте SuppressWarnings для всего класса. Это может маскировать критические предупреждения.

Если вы используете аннотацию SuppressWarnings для метода или конструктор длиной более одной строки, вы можете перенести его на локальный объявление переменной. Возможно, вам придется объявить новую локальную переменную, но ее ценность он.

Нельзя помещать аннотацию SuppressWarnings в оператор return, потому что это не объявление [JLS, 9.7]. Возможно, у вас возникнет соблазн поставить аннотацию по всему методу, но не. Вместо этого объявите локальную переменную, чтобы вернуть значение и аннотировать его объявление