Type safety: Unchecked cast from Object to List<MyObject>
Solution 1
Well, I finally managed to find a solution.
Just as @Medo42 said:
Another option is to check for and cast to List as the instanceof error suggests. Then you can iterate over the elements in the list and check if they are actually all instances of MyObject, and copy them to a new List.
Even though I did not went through the process of creating a whole new object in order to make this particular case to work "warning-less" this was the right direction to go.
So I took @lokoko 's idea and use it in a new setItems()
method, with an Object
parameter instead of a List<MyObject>
in order to make sure
The result code is the following:
public void setItems(List<MyObject> var){
this.list = var;
}
public void setItems(Object var){
List<MyObject> result = new ArrayList<MyObject>();
if (var instanceof List){
for(int i = 0; i < ((List<?>)var).size(); i++){
Object item = ((List<?>) var).get(i);
if(item instanceof MyObject){
result.add((MyObject) item);
}
}
}
setItems(result);
}
Thanks everyone for your help!
Solution 2
If all you have to work from is an Object
, then you can't check at runtime that you actually have a List<MyObject>
, because the generic type MyObject
is only used for compile-time type checking, it is not available at runtime. This is why you get an error when you try to add the instanceof
check.
If you are sure that your Object
really is always a List<MyObject>
then I'd say the @SuppressWarnings
is OK, if you document why you are sure it is not a problem.
If you absolutely want to avoid a warning though, you could create your own List
implementation (say, MyObjectList
) that is not itself generic but implements List<MyObject>
. Then you can do an instanceof
check against MyObjectList
at runtime.
Another option is to check for and cast to List<?>
as the instanceof
error suggests. Then you can iterate over the elements in the list and check if they are actually all instances of MyObject, and copy them to a new List<MyObject>
.
Solution 3
Try something like this :
List<?> result = (List<?>) results.values;
for (Object object : result) {
if (object instanceof MyObject) {
tempList.add((MyObject) object); // <-- add to temp
}
}
filteredItems = tempList; // <-- set filtered
Solution 4
You can perform the checking before passing it to setItems()
.
final Object myListObj = reuslts.values;
if(myListObj instanceof List<?>) {
if(((List<?>)myListObj).get(0) instanceof MyObject)
// You can safely suppress the warning here because you made sure it is a List containing MyObject
MyObjectAdapter.this.setItems((List<? extends MyObject>) myListObj);
}
However, you need to change your setItems()
method accordingly:
public void setItems(List<? extends MyObject> list) {
// Your code here
}
Related videos on Youtube
Eloi Navarro
Android developer since 2011. UX/UI enthusiast I like to make my code clean and reusable. Developers are the artisans of code, there is always a lot more of creativity than it seems "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live." John F. Woods
Updated on March 24, 2020Comments
-
Eloi Navarro about 4 years
I have a ListView listing a custom object (let's say
MyObject
).I want to filter it dynamically through an
EditText
so I had to implement agetFilter()
with a publishResults method:@Override protected void publishResults(CharSequence constraint, FilterResults results) { MyObjectAdapter.this.setItems((List<MyObject>) results.values); MyObjectAdapter.this.notifyDataSetChanged(); }
At this point, Eclipse complains:
Type safety: Unchecked cast from Object to List<MyObject>
I am sure this cast will always be true, but Eclipse only suggests to add
@SuppressWarnings("unchecked")
but I'm totally againstSuppressWarnings
because it's only hiding the problem, not a solution...I tried adding:
if(results.values instanceof List<MyObject>)
But Eclipse complains again, and this solves nothing...
Cannot perform instanceof check against parameterized type List<MyObject>. Use the form List<?>
I know the casting will always be correct, but which is the proper way to make the code to be sure
results.values
is actually aList<MyObject>
?Thanks in advance!
-
ROMANIA_engineer over 8 years
-
-
Medo42 over 11 yearsThis check only ensures that the first object in the list is a
MyObject
, so the only thing you have shown is that the list can contain such elements - not that it actually is aList<MyObject>
or even aList<? extends MyObject>
. Rather, you have shown that it is aList<? super MyObject>
. -
Lawrence Choy over 11 yearsYou are correct. However, a
List<String>
can never contains an element ofInteger
right? IfMyObject
has no subclass this works well. Even if the objects insideextends MyObject
, they all contains necessary interface or functions thatMyObjectAdapter
required, because method signature decladedMyObject
, not other subclasses. -
Medo42 over 11 yearsTechnically, a
List<String>
can contain anInteger
because the generic type of the list is not enforced at runtime. But even if you had that guarantee and even ifMyObject
has no subclasses your suggestion isn't valid. Imagine aList<Object>
that contains oneMyObject
and one String. Your check would cast that toList<? extends MyObject>
because the first element happens to be aMyObject
, but trying to get the second element throught that casted list would cause aClassCastException
. -
Eloi Navarro over 11 yearsYour solution helped me to figure out how to solve my problem, thx!
-
Android Dev almost 2 yearsFor me I did: val imageList: List<Any> = snapshot.value as ArrayList<Any>