Затмение дает мне предупреждение о следующей форме:
Безопасность типов: непроверенное приведение из объекта в 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.
enum
или даже экземплярыClass<T>
), чтобы вы могли взглянуть на него и знать, что это безопасно.Ответы:
Очевидный ответ, конечно же, состоит не в том, чтобы делать непроверенный актерский состав.
Если это абсолютно необходимо, то хотя бы попытайтесь ограничить объем
@SuppressWarnings
аннотации. Согласно его Javadocs , он может идти на локальные переменные; таким образом, это даже не влияет на весь метод.Пример:
Нет никакого способа определить,
Map
действительно ли должны иметь общие параметры<String, String>
. Вы должны заранее знать, какими должны быть параметры (или вы узнаете, когда получите aClassCastException
). Вот почему код генерирует предупреждение, потому что компилятор не может знать, безопасен ли он.источник
String s = (String) new Object() ;
получает предупреждения, даже если компилятор не знает, что приведение безопасно. Предупреждение состоит в том, что компилятор (а) не знает, что приведение является безопасным И (b) не будет генерировать полную проверку во время выполнения в точке приведения. Будет проверка, что этоHashmap
, но не будет проверки, что этоHashMap<String,String>
.К сожалению, здесь нет хороших вариантов. Помните, что цель всего этого - сохранить безопасность типов. « Java Generics » предлагает решение для работы с неуниверсализированными унаследованными библиотеками, и в частности, есть одна, называемая «техникой пустого цикла» в разделе 8.2. В основном, сделайте небезопасный бросок и подавите предупреждение. Затем переберите карту так:
Если обнаружится непредвиденный тип, вы получите среду выполнения
ClassCastException
, но, по крайней мере, это произойдет близко к источнику проблемы.источник
Ух ты; Думаю, я разобрался с ответом на свой вопрос. Я просто не уверен, что оно того стоит! :)
Проблема в том, что актерский состав не проверен. Итак, вы должны проверить это сами. Невозможно просто проверить параметризованный тип с помощью instanceof, поскольку информация о параметризованном типе недоступна во время выполнения, поскольку она была стерта во время компиляции.
Но вы можете выполнить проверку каждого элемента в хэше с помощью instanceof, и при этом вы можете создать новый хеш, который является типобезопасным. И вы не будете провоцировать никаких предупреждений.
Благодаря mmyers и Esko Luontola, я параметризовал код, который я изначально написал здесь, так что его можно поместить в служебный класс где-нибудь и использовать для любого параметризованного HashMap. Если вы хотите лучше понять его и не очень знакомы с дженериками, я рекомендую просмотреть историю редактирования этого ответа.
Это большая работа, возможно, за очень маленькую награду ... Я не уверен, буду ли я ее использовать или нет. Буду признателен за любые комментарии относительно того, думают ли люди, что это того стоит или нет. Кроме того, я был бы признателен за предложения по улучшению: есть ли что-то лучшее, что я могу сделать, кроме как бросить AssertionErrors? Есть ли что-то лучшее, что я мог бы бросить? Должен ли я сделать это проверенным исключением?
источник
В настройках Eclipse перейдите в раздел Java-> Компилятор-> Ошибки / Предупреждения-> Общие типы и установите
Ignore unavoidable generic type problems
флажок.Это удовлетворяет цели вопроса, т.е.
если не дух.
источник
uses unchecked or unsafe operations.
ошибку " "javac
, но добавление@SuppressWarnings("unchecked")
делает Eclipse несчастным, утверждая, что подавление было ненужным. Снятие отметки с этого поля делает Eclipse иjavac
ведет себя так же, чего я и хотел. Явное подавление предупреждения в коде намного яснее, чем подавление его повсюду в Eclipse.Вы можете создать служебный класс, подобный следующему, и использовать его для подавления непроверенного предупреждения.
Вы можете использовать его следующим образом:
Еще несколько обсуждений по этому вопросу здесь: http://cleveralias.blogs.com/thought_spearmints/2006/01/suppresswarning.html
источник
vi
? Вы шутите?Это сложно, но вот мои нынешние мысли:
Если ваш API возвращает Object, то вы ничего не можете сделать - несмотря ни на что, вы будете слепо использовать объект. Вы можете разрешить Java бросать ClassCastExceptions, или вы можете проверить каждый элемент самостоятельно и выбросить Assertions или IllegalArgumentExceptions или некоторые другие, но все эти проверки во время выполнения эквивалентны. Вы должны подавить неконтролируемое приведение во время компиляции независимо от того, что вы делаете во время выполнения.
Я просто предпочел бы слепое приведение и позволить JVM выполнить проверку во время выполнения для меня, поскольку мы «знаем», что должен возвращать API, и обычно готовы предположить, что API работает. Используйте дженерики везде над актерами, если они вам нужны. Вы на самом деле ничего не покупаете там, так как у вас все еще есть один слепой бросок, но по крайней мере вы можете использовать дженерики оттуда, чтобы JVM могла помочь вам избежать слепых бросков в других частях вашего кода.
В этом конкретном случае, по-видимому, вы можете увидеть вызов SetAttribute и увидеть, что тип входит, так что просто слепое приведение типа к тому же на выходе не аморально. Добавьте комментарий со ссылкой на SetAttribute и покончите с этим.
источник
Вот сокращенный пример, который позволяет избежать предупреждения о «непроверенном использовании» , используя две стратегии, упомянутые в других ответах.
Передайте класс интересующего вас типа в качестве параметра во время выполнения (
Class<T> inputElementClazz
). Тогда вы можете использовать:inputElementClazz.cast(anyObject);
Для приведения типов Коллекции используйте подстановочный знак? вместо универсального типа T для подтверждения того, что вы действительно не знаете, какие объекты ожидать от унаследованного кода (
Collection<?> unknownTypeCollection
). В конце концов, это то, что хочет сказать нам предупреждение «непроверенный актерский состав»: мы не можем быть уверены, что мы получилиCollection<T>
, поэтому честное дело - использовать aCollection<?>
. Если это абсолютно необходимо, можно собрать коллекцию известного типа (Collection<T> knownTypeCollection
).Унаследованный код, описанный в приведенном ниже примере, имеет атрибут «input» в StructuredViewer (StructuredViewer - это виджет дерева или таблицы, «input» - модель данных, стоящая за ним). Этим «входом» может быть любой вид Java Collection.
Естественно, приведенный выше код может выдавать ошибки времени выполнения, если мы используем устаревший код с неправильными типами данных (например, если мы зададим массив в качестве «входа» StructuredViewer вместо Java Collection).
Пример вызова метода:
источник
В мире HTTP Session вы не можете избежать преобразования, поскольку API написан именно так (только принимает и возвращает
Object
).Однако, немного поработав, вы легко сможете избежать неконтролируемого актерского состава. Это означает, что он превратится в традиционный актерский состав, дающий
ClassCastException
право тут же в случае ошибки). Непроверенное исключение может превратиться вCCE
любой момент позже вместо точки приведения (именно поэтому это отдельное предупреждение).Замените HashMap выделенным классом:
Затем приведите к этому классу вместо,
Map<String,String>
и все будет проверено в том месте, где вы пишете свой код. Не неожиданноClassCastExceptions
позже.источник
В Android Studio, если вы хотите отключить проверку, вы можете использовать:
источник
В этом конкретном случае я бы не сохранял Maps непосредственно в HttpSession, а вместо этого представлял собой экземпляр моего собственного класса, который, в свою очередь, содержит Map (деталь реализации класса). Тогда вы можете быть уверены, что элементы на карте имеют правильный тип.
Но если вы все равно хотите проверить, что содержимое карты имеет правильный тип, вы можете использовать код, подобный следующему:
источник
Служебная функция Objects.Unchecked в ответе Эско Луонтолы (Esko Luontola) выше - отличный способ избежать беспорядка в программе.
Если вы не хотите, чтобы SuppressWarnings применялся ко всему методу, Java заставит вас поместить его в локальный метод. Если вам нужен приведение к члену, это может привести к такому коду:
Использование утилиты намного чище, и все еще очевидно, что вы делаете:
ПРИМЕЧАНИЕ: я считаю важным добавить, что иногда предупреждение действительно означает, что вы делаете что-то не так, например:
Компилятор говорит вам, что это приведение НЕ будет проверяться во время выполнения, поэтому ошибка времени выполнения не будет возникать, пока вы не попытаетесь получить доступ к данным в универсальном контейнере.
источник
Подавление предупреждений не является решением. Вы не должны делать двухуровневое приведение в одном утверждении.
источник
Быстрое предположение, если вы публикуете свой код, можно сказать наверняка, но вы, возможно, сделали что-то вроде
который выдаст предупреждение, когда вам нужно сделать
возможно, стоит посмотреть на
Обобщения в языке программирования Java
если вы не знакомы с тем, что необходимо сделать.
источник
Возможно, я неправильно понял вопрос (пример и пара окружающих строк были бы хорошими), но почему вы не всегда используете соответствующий интерфейс (и Java5 +)? Я не вижу причин, по которым вы бы хотели бросить
HashMap
вместоMap<KeyType,ValueType>
. На самом деле, я не могу себе представить какой - либо причины , чтобы установить тип переменнойHashMap
вместоMap
.И почему источник
Object
? Это тип параметра устаревшей коллекции? Если это так, используйте дженерики и укажите нужный тип.источник
Если мне нужно использовать API, который не поддерживает Generics ... Я пытаюсь изолировать эти вызовы в процедурах-оболочках с как можно меньшим количеством строк. Затем я использую аннотацию SuppressWarnings, а также добавляю приведения типов безопасности одновременно.
Это просто личное предпочтение держать вещи как можно более аккуратными.
источник
Возьмите этот, это намного быстрее, чем создание нового HashMap, если он уже один, но все еще безопасный, так как каждый элемент проверяется по его типу ...
источник
key.isAssignableFrom(e.getKey().getClass())
можно записать какkey.isInstance(e.getKey())
Просто проверь его, прежде чем разыграть.
И для всех, кто спрашивает, довольно часто можно получать объекты, в которых вы не уверены, какого типа. Множество устаревших реализаций "SOA" передают различные объекты, которым вы не всегда должны доверять. (Ужасы!)
РЕДАКТИРОВАТЬ Один раз изменил код примера, чтобы он соответствовал обновлениям автора, и после некоторых комментариев я вижу, что instanceof не очень хорошо работает с генериками. Однако изменение проверки для проверки внешнего объекта, похоже, хорошо работает с компилятором командной строки. Пересмотренный пример теперь опубликован.
источник
Почти каждая проблема в области компьютерных наук может быть решена путем добавления уровня косвенности * или чего-то еще.
Итак, представьте неуниверсальный объект более высокого уровня, чем a
Map
. Без контекста это не будет выглядеть очень убедительно, но в любом случае:* За исключением слишком большого количества уровней косвенности.
источник
Вот один из способов справиться с этим, когда переопределяю
equals()
операцию.Кажется, это работает в Java 8 (даже скомпилировано с
-Xlint:unchecked
)источник
Если вы уверены, что типом, возвращаемым session.getAttribute (), является HashMap, то вы не можете типизировать этот точный тип, а полагаться только на проверку универсального HashMap.
В этом случае Eclipse будет удивлять предупреждениями, но, конечно, это может привести к ошибкам во время выполнения, которые сложно отладить. Я использую этот подход только в некритическом контексте.
источник
Два способа, один из которых полностью избегает тег, другой использует непослушный, но приятный служебный метод.
Проблема заключается в том, что коллекции предварительно обобщены ...
Я полагаю, что практическое правило гласит: «бросать объекты по одной вещи за раз» - это означает, что при использовании необработанных классов в обобщенном мире это происходит потому, что вы не знаете находится на этой карте <?,?> (и действительно, JVM может даже обнаружить, что это даже не карта!), когда вы думаете об этом, вы не можете разыграть ее. Если у вас есть Map <String,?> Map2, то HashSet <String> keys = (HashSet <String>) map2.keySet () не выдает предупреждение, несмотря на то, что это «акт веры» для компилятора (потому что это может оказаться TreeSet) ... но это всего лишь один акт веры.
PS на возражение, что повторение, как в моем первом случае, «скучно» и «требует времени», ответ «нет боли, нет выгоды»: обобщенная коллекция гарантированно содержит Map.Entry <String, String> s и ничего остальное. Вы должны заплатить за эту гарантию. При систематическом использовании непатентованных средств этот платеж, красиво, принимает форму соответствия кодирования, а не машинного времени!
Одна школа мысли может сказать, что вы должны установить настройки Eclipse, чтобы делать такие неконтролируемые ошибки приведения, а не предупреждения. В этом случае вам придется использовать мой первый способ.
источник
Это заставляет предупреждения уходить ...
источник
Решение: отключите это предупреждение в Eclipse. Не @SuppressWarnings, просто отключите его полностью.
Некоторые из «решений», представленных выше, являются выходом из строя, делая код нечитаемым для подавления глупого предупреждения.
источник
@SuppressWarnings
не делает код вообще нечитаемым.