Type safety: Unchecked cast
Well, first of all, you're wasting memory with the new HashMap
creation call. Your second line completely disregards the reference to this created hashmap, making it then available to the garbage collector. So, don't do that, use:
private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
Secondly, the compiler is complaining that you cast the object to a HashMap
without checking if it is a HashMap
. But, even if you were to do:
if(getApplicationContext().getBean("someMap") instanceof HashMap) {
private Map<String, String> someMap = (HashMap<String, String>)getApplicationContext().getBean("someMap");
}
You would probably still get this warning. The problem is, getBean
returns Object
, so it is unknown what the type is. Converting it to HashMap
directly would not cause the problem with the second case (and perhaps there would not be a warning in the first case, I'm not sure how pedantic the Java compiler is with warnings for Java 5). However, you are converting it to a HashMap<String, String>
.
HashMaps are really maps that take an object as a key and have an object as a value, HashMap<Object, Object>
if you will. Thus, there is no guarantee that when you get your bean that it can be represented as a HashMap<String, String>
because you could have HashMap<Date, Calendar>
because the non-generic representation that is returned can have any objects.
If the code compiles, and you can execute String value = map.get("thisString");
without any errors, don't worry about this warning. But if the map isn't completely of string keys to string values, you will get a ClassCastException
at runtime, because the generics cannot block this from happening in this case.
How do I address unchecked cast warnings?
Wow; I think I figured out the answer to my own question. I'm just not sure it's worth it! :)
The problem is the cast isn't checked. So, you have to check it yourself. You can't just check a parameterized type with instanceof, because the parameterized type information is unavailable at runtime, having been erased at compile time.
But, you can perform a check on each and every item in the hash, with instanceof, and in doing so, you can construct a new hash that is type-safe. And you won't provoke any warnings.
Thanks to mmyers and Esko Luontola, I've parameterized the code I originally wrote here, so it can be wrapped up in a utility class somewhere and used for any parameterized HashMap. If you want to understand it better and aren't very familiar with generics, I encourage viewing the edit history of this answer.
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;
}
That's a lot of work, possibly for very little reward... I'm not sure if I'll use it or not. I'd appreciate any comments as to whether people think it's worth it or not. Also, I'd appreciate improvement suggestions: is there something better I can do besides throw AssertionErrors? Is there something better I could throw? Should I make it a checked Exception?
Type safety: Unchecked cast from Object to List
Your second solution won't help (due to Type Erasure), and will cause other problems too so probably not a good idea.
The first method will probably work in practice, but is a bit dodgy really. There's a subtle (but huge) difference between sub-classing Generic types and subclassing their parameters in Java - i.e. ArrayList<Integer>
is not a subclass of ArrayList<Object>
, but ArrayList<String>
is a sub-type of Collection<String>
: see a more fun example. More formal Computer Sciencey background in Wikipedia entry on Covariance.
So, IMO you should keep the casting there, keep the (necessary) annotation, and catch the ClassCastException
to make sure that the exceptional (hence the name) cases are covered.
How to get rid of Type safety: Unchecked cast from Object to Map String,String
You can't.
Since Authentication
simply defines return value of getDetails()
as an Object
, you have to cast, and although the type Map
will be checked at runtime, there is still no guarantee that it maps String
to String
(because of type erasure).
This means that you may get a ClassCastException
at some later point, when the Map
is used. That is what the warning is trying to tell you, and you accept responsibility for that by adding @SuppressWarnings
.
How to fix 'Unchecked cast from MyClass to T'
The solution is to use T
as the type here and then you can remove your casts:
// before:
// SonarContainPaging sonarObject = getSonarObjectFromPage(url, uriVariables, klass, page);
// after:
T sonarObject = getSonarObjectFromPage(url, uriVariables, klass, page);
Since according to your comment, getSonarObjectFromPage
returns T
, where T
is the class you pass it in:
<T extends SonarContainPaging> T getSonarObjectFromPage(String url, Map<String, Object> uriVariables, Class<T> klass, List<T> page)
In this case you passed the class klass
, which is a Class<T>
, so getSonarObjectFromPage
will return a T
as well.
Type safety: Unchecked cast from Object
Yes - this is a natural consequence of type erasure. If o
is actually an instance of Action<String>
that won't be caught by the cast - you'll only see the problem when you try to use it, passing in a ClientInterface
instead of a string.
You can get rid of the warning using:
@SuppressWarnings("unchecked")
as a function annotation, but you can't easily sort out the underlying problem :(
Unchecked Cast warning - shows up for Type parameters but not for Concrete types?
Unchecked cast is flagged as the compiler does not know until the runtime if the type represented by the
Supertype
will ever match theSubType
.
That is incorrect. Not even the runtime knows whether your list is a ArrayList<String>
or a ArrayList<Integer>
. As far as the runtime is concerned, your list is an ArrayList
(This is because of type erasure). This is why casting a List<?>
to a List<String>
cannot be checked by the runtime. The runtime does not know what a List<String>
is - it only knows about List
. To the runtime, no checks are needed, since you are just casting from List
to List
, which always succeeds. In fact, nothing is done for this cast at runtime - it is a completely unchecked cast.
As a result, this code runs without throwing an exception:
List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.size());
It will throw an exception, however, if you did:
List<String> stringList = new ArrayList<>();
stringList.add("foo");
List<Integer> integerList = (List<Integer>)(List<?>)stringList;
System.out.println(integerList.get(0) - 1);
Now, you are getting an integer out of the list, and doing some integer-specific operations to it. But the list contains "foo"
, which isn't an integer. The compiler inserts an implicit cast to cast integerList.get(0)
to Integer
, and that cast failed. Note that this is a checked cast, because the runtime knows about the type Integer
.
The cast from Number
to Double
is also checked, because the runtime knows about Double
.
Side note: there are also "partially unchecked casts", which are things like casting from Object
to ArrayList<String>
. The runtime can check whether the Object
is an ArrayList
, but it cannot check whether it is an array list of strings.
See all the rules for what is checked and what is unchecked here.
Type safety: Unchecked cast from WebElement to List WebElement
WebElement ele = getObject(locator);
List<WebElement> ls = (List<WebElement>) ele;
You are casting List
to WebElement
and that is not valid. I believe in your getObject
method you are using findElement
method to identify the locator. Instead of that use findElements
method to get List
of WebElement
Try like below,
List<WebElement> ls = driver.findElements(By.xpath(locator));
How to avoid warning Type safety: Unchecked cast from Object to ArrayList Facility
The problem is that the cast will succeed as long as the returned object is an ArrayList
, but it can't guarantee that every element is a Facility
because of erasure. You can do that yourself, if you wish.
ArrayList<Facility> facilities =
((ArrayList<?>) xstream.fromXML(xml)).stream()
.filter(Facility.class::isInstance)
.map(Facility.class::cast)
.collect(Collectors.toCollection(ArrayList::new));
Related Topics
Running Code After Spring Boot Starts
Getting the Filenames of All Files in a Folder
Java 8: Lambda-Streams, Filter by Method with Exception
How to Hash Some String with Sha256 in Java
Is There a Java API That Can Create Rich Word Documents
How to Randomize Two Arraylists in the Same Fashion
How to Run Certain Task Every Day at a Particular Time Using Scheduledexecutorservice
Mod in Java Produces Negative Numbers
How to Read System Environment Variable in Spring Applicationcontext
Jpql Create New Object in Select Statement - Avoid or Embrace
How to Sort a List Alphabetically
How to Read the Value of a Annotation in Java
Connection to Db Dies After >4<24 in Spring-Boot JPA Hibernate