Вопрос-ответ

How do I address unchecked cast warnings?

Как мне устранить непроверенные предупреждения о приведении?

Eclipse выдает мне предупреждение следующего вида:


Безопасность типов: непроверенное приведение из объекта в HashMap


Это результат вызова API, который я не могу контролировать, который возвращает Object:

HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
HashMap<String, String> theHash = (HashMap<String, String>)session.getAttribute("attributeKey");
return theHash;
}

Я бы хотел по возможности избегать предупреждений Eclipse, поскольку теоретически они указывают, по крайней мере, на потенциальную проблему с кодом. Однако я пока не нашел хорошего способа устранить эту проблему. Я могу извлечь единственную строку, связанную с методом, отдельно и добавить @SuppressWarnings("unchecked") к этому методу, таким образом ограничивая влияние наличия блока кода, в котором я игнорирую предупреждения. Есть варианты получше? Я не хочу отключать эти предупреждения в Eclipse.

До того, как я пришел к коду, он был проще, но все равно вызывал предупреждения:

HashMap getItems(javax.servlet.http.HttpSession session) {
HashMap theHash = (HashMap)session.getAttribute("attributeKey");
return theHash;
}

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

HashMap items = getItems(session);
items.put("this", "that");

Type safety: The method put(Object, Object) belongs to the raw type HashMap. References to generic type HashMap<K,V> should be parameterized.
Переведено автоматически
Ответ 1

Очевидный ответ, конечно, не выполнять непроверенное приведение.

Если это абсолютно необходимо, то хотя бы попробуйте ограничить область применения @SuppressWarnings аннотации. Согласно его Javadocs, он может работать с локальными переменными; таким образом, это даже не влияет на весь метод.

Пример:

@SuppressWarnings("unchecked")
Map<String, String> myMap = (Map<String, String>) deserializeMap();

Нет способа определить, Map действительно ли должен иметь общие параметры <String, String>. Вы должны заранее знать, какими должны быть параметры (или вы узнаете, когда получите ClassCastException). Вот почему код генерирует предупреждение, потому что компилятор не может знать, безопасно ли это.

Ответ 2

К сожалению, здесь нет хороших вариантов. Помните, цель всего этого - сохранить безопасность типов. "Java Generics" предлагает решение для работы с унаследованными библиотеками, не являющимися универсальными, и в разделе 8.2 есть одно, в частности, называемое "техникой пустого цикла". По сути, создайте небезопасное приведение и подавите предупреждение. Затем выполните цикл по карте следующим образом:

@SuppressWarnings("unchecked")
Map<String, Number> map = getMap();
for (String s : map.keySet());
for (Number n : map.values());

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

Ответ 3

Вау; Кажется, я нашел ответ на свой собственный вопрос. Я просто не уверен, что оно того стоит! :)

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

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

Благодаря mmyers и Esko Luontola я параметризовал код, который изначально написал здесь, так что его можно обернуть где-нибудь в служебный класс и использовать для любой параметризованной хэш-карты. Если вы хотите лучше понять это и не очень знакомы с обобщениями, я рекомендую просмотреть историю редактирования этого ответа.

public static <K, V> HashMap<K, V> castHash(HashMap input,
Class<K> keyClass,
Class<V> valueClass)
{
HashMap<K, V> output = new HashMap<K, V>();
if (input == null)
return output;
for (Object key: input.keySet().toArray()) {
if ((key == null) || (keyClass.isAssignableFrom(key.getClass()))) {
Object value = input.get(key);
if ((value == null) || (valueClass.isAssignableFrom(value.getClass()))) {
K k = keyClass.cast(key);
V v = valueClass.cast(value);
output.put(k, v);
} else {
throw new AssertionError(
"Cannot cast to HashMap<"+ keyClass.getSimpleName()
+", "+ valueClass.getSimpleName() +">"
+", value "+ value +" is not a "+ valueClass.getSimpleName()
);
}
} else {
throw new AssertionError(
"Cannot cast to HashMap<"+ keyClass.getSimpleName()
+", "+ valueClass.getSimpleName() +">"
+", key "+ key +" is not a " + keyClass.getSimpleName()
);
}
}
return output;
}

Это большая работа, возможно, за очень небольшое вознаграждение... Я не уверен, буду ли я использовать это или нет. Я был бы признателен за любые комментарии относительно того, считают ли люди, что оно того стоит или нет. Кроме того, я был бы признателен за предложения по улучшению: могу ли я сделать что-нибудь получше, кроме выдвижения AssertionErrors? Есть ли что-нибудь получше, что я мог бы выдать? Должен ли я сделать это проверяемым исключением?

Ответ 4

В настройках Eclipse перейдите в Java-> Компилятор-> Ошибки / предупреждения-> Универсальные типы и установите флажок Ignore unavoidable generic type problems.

Это удовлетворяет цели вопроса, т.Е.


Я бы хотел избежать предупреждений Eclipse...


если не дух.

java generics