How do I address unchecked cast warnings?

后端 未结 23 1177
醉梦人生
醉梦人生 2020-11-22 03:06

Eclipse is giving me a warning of the following form:

Type safety: Unchecked cast from Object to HashMap

This is from a call to

相关标签:
23条回答
  • 2020-11-22 03:42

    You can create a utility class like the following, and use it to suppress the unchecked warning.

    public class Objects {
    
        /**
         * Helps to avoid using {@code @SuppressWarnings({"unchecked"})} when casting to a generic type.
         */
        @SuppressWarnings({"unchecked"})
        public static <T> T uncheckedCast(Object obj) {
            return (T) obj;
        }
    }
    

    You can use it as follows:

    import static Objects.uncheckedCast;
    ...
    
    HashMap<String, String> getItems(javax.servlet.http.HttpSession session) {
          return uncheckedCast(session.getAttribute("attributeKey"));
    }
    

    Some more discussion about this is here: http://cleveralias.blogs.com/thought_spearmints/2006/01/suppresswarning.html

    0 讨论(0)
  • 2020-11-22 03:43

    Here is a shortened example that avoids the "unchecked cast" warning by employing two strategies mentioned in other answers.

    1. Pass down the Class of the type of interest as a parameter at runtime (Class<T> inputElementClazz). Then you can use: inputElementClazz.cast(anyObject);

    2. For type casting of a Collection, use the wildcard ? instead of a generic type T to acknowledge that you indeed do not know what kind of objects to expect from the legacy code (Collection<?> unknownTypeCollection). After all, this is what the "unchecked cast" warning wants to tell us: We cannot be sure that we get a Collection<T>, so the honest thing to do is to use a Collection<?>. If absolutely needed, a collection of a known type can still be built (Collection<T> knownTypeCollection).

    The legacy code interfaced in the example below has an attribute "input" in the StructuredViewer (StructuredViewer is a tree or table widget, "input" is the data model behind it). This "input" could be any kind of Java Collection.

    public void dragFinished(StructuredViewer structuredViewer, Class<T> inputElementClazz) {
        IStructuredSelection selection = (IStructuredSelection) structuredViewer.getSelection();
        // legacy code returns an Object from getFirstElement,
        // the developer knows/hopes it is of type inputElementClazz, but the compiler cannot know
        T firstElement = inputElementClazz.cast(selection.getFirstElement());
    
        // legacy code returns an object from getInput, so we deal with it as a Collection<?>
        Collection<?> unknownTypeCollection = (Collection<?>) structuredViewer.getInput();
    
        // for some operations we do not even need a collection with known types
        unknownTypeCollection.remove(firstElement);
    
        // nothing prevents us from building a Collection of a known type, should we really need one
        Collection<T> knownTypeCollection = new ArrayList<T>();
        for (Object object : unknownTypeCollection) {
            T aT = inputElementClazz.cast(object);
            knownTypeCollection.add(aT);
            System.out.println(aT.getClass());
        }
    
        structuredViewer.refresh();
    }
    

    Naturally, the code above can give runtime errors if we use the legacy code with the wrong data types (e.g. if we set an array as the "input" of the StructuredViewer instead of a Java Collection).

    Example of calling the method:

    dragFinishedStrategy.dragFinished(viewer, Product.class);
    
    0 讨论(0)
  • 2020-11-22 03:43

    In Android Studio if you want to disable inspection you can use:

    //noinspection unchecked
    Map<String, String> myMap = (Map<String, String>) deserializeMap();
    
    0 讨论(0)
  • 2020-11-22 03:45

    In this particular case, I would not store Maps into the HttpSession directly, but instead an instance of my own class, which in turn contains a Map (an implementation detail of the class). Then you can be sure that the elements in the map are of the right type.

    But if you anyways want to check that the contents of the Map are of right type, you could use a code like this:

    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("a", 1);
        map.put("b", 2);
        Object obj = map;
    
        Map<String, Integer> ok = safeCastMap(obj, String.class, Integer.class);
        Map<String, String> error = safeCastMap(obj, String.class, String.class);
    }
    
    @SuppressWarnings({"unchecked"})
    public static <K, V> Map<K, V> safeCastMap(Object map, Class<K> keyType, Class<V> valueType) {
        checkMap(map);
        checkMapContents(keyType, valueType, (Map<?, ?>) map);
        return (Map<K, V>) map;
    }
    
    private static void checkMap(Object map) {
        checkType(Map.class, map);
    }
    
    private static <K, V> void checkMapContents(Class<K> keyType, Class<V> valueType, Map<?, ?> map) {
        for (Map.Entry<?, ?> entry : map.entrySet()) {
            checkType(keyType, entry.getKey());
            checkType(valueType, entry.getValue());
        }
    }
    
    private static <K> void checkType(Class<K> expectedType, Object obj) {
        if (!expectedType.isInstance(obj)) {
            throw new IllegalArgumentException("Expected " + expectedType + " but was " + obj.getClass() + ": " + obj);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 03:45

    The Objects.Unchecked utility function in the answer above by Esko Luontola is a great way to avoid program clutter.

    If you don't want the SuppressWarnings on an entire method, Java forces you to put it on a local. If you need a cast on a member it can lead to code like this:

    @SuppressWarnings("unchecked")
    Vector<String> watchedSymbolsClone = (Vector<String>) watchedSymbols.clone();
    this.watchedSymbols = watchedSymbolsClone;
    

    Using the utility is much cleaner, and it's still obvious what you are doing:

    this.watchedSymbols = Objects.uncheckedCast(watchedSymbols.clone());
    

    NOTE: I feel its important to add that sometimes the warning really means you are doing something wrong like :

    ArrayList<Integer> intList = new ArrayList<Integer>();
    intList.add(1);
    Object intListObject = intList; 
    
     // this line gives an unchecked warning - but no runtime error
    ArrayList<String> stringList  = (ArrayList<String>) intListObject;
    System.out.println(stringList.get(0)); // cast exception will be given here
    

    What the compiler is telling you is that this cast will NOT be checked at runtime, so no runtime error will be raised until you try to access the data in the generic container.

    0 讨论(0)
  • 2020-11-22 03:45

    A quick guess if you post your code can say for sure but you might have done something along the lines of

    HashMap<String, Object> test = new HashMap();
    

    which will produce the warning when you need to do

    HashMap<String, Object> test = new HashMap<String, Object>();
    

    it might be worth looking at

    Generics in the Java Programming Language

    if your unfamiliar with what needs to be done.

    0 讨论(0)
提交回复
热议问题