Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Unchecked cast from X to Y / how to implement castOrNull

I have implemented this function:

 static <X,Y> Y castOrNull(X obj) {
  try {
   return (Y)obj;
  }
  catch(ClassCastException e) {
   return null;
  }
 }

This gives me the compiler warning:

Type safety: Unchecked cast from X to Y

Which I don't exactly understand. Isn't the try/catch which I am doing here a check for it? Can I ignore the warning?

Will my function work as expected or not? How would I implement it correctly?

I also tried with a obj instanceof Y check but that doesn't work because of the way Java handle generics.

Btw., this function seems quite useful to me (to make some other code more clean). I wonder if such a function may already exist in Java?


One example where I want to use it:

    void removeEmptyRawStrings() {
        for(Iterator<Entity> e = entities.iterator(); e.hasNext();) {
            RawString s = castOrNull(e.next());
            if(s != null && s.content.isEmpty()) e.remove();
        }
    }

I have cases like these quite often in my code. And I think this is more readable and simpler than anything else. But please give me a better suggestion if you have any about how to make that code even more simple.

like image 998
Albert Avatar asked Oct 14 '10 13:10

Albert


People also ask

How do you handle unchecked cast in Java?

If we can't eliminate the “unchecked cast” warning and we're sure that the code provoking the warning is typesafe, we can suppress the warning using the SuppressWarnings(“unchecked”) annotation. When we use the @SuppressWarning(“unchecked”) annotation, we should always put it on the smallest scope possible.

What are unchecked warnings in Java?

An unchecked warning tells a programmer that a cast may cause a program to throw an exception somewhere else. Suppressing the warning with @SuppressWarnings("unchecked") tells the compiler that the programmer believes the code to be safe and won't cause unexpected exceptions.


4 Answers

So the problem here is that the generic parameter Y when used for dynamic casting is treated as Object. It will never throw a CCE. You get a CCE thrown in the calling method, as you have broken static type safety.

Also X is entirely pointless here:

Almost certainly the correct solution is not to attempt anything like this. null is bad. Casting is bad.

However, if you are determined to write nonsense, you can pass the Class object:

public static <T> T evilMethod(Class<T> clazz, Object obj) {
    try {
        return clazz.cast(obj);
    } catch (ClassCastException exc) {
        return null;
    }
}
like image 154
Tom Hawtin - tackline Avatar answered Oct 17 '22 13:10

Tom Hawtin - tackline


I'm not entirely sure it will work as expected. (Depends on what you expect of course :-) but this code will for instance result in a java.lang.ClassCastException (ideone):

public class Main {

    public static void main(String[] args) {
        Integer o = Main.<String, Integer>castOrNull("hello");
    }


    public static <X, Y> Y castOrNull(X obj) {
        try {
            return (Y) obj;
        } catch (ClassCastException e) {
            return null;
        }
    }
}

@Tom Hawtin got the "correct" solution.

like image 38
aioobe Avatar answered Oct 17 '22 14:10

aioobe


You can suppress the warning in this method if you know for sure that it's not a problem by annotating it with @SuppressWarnings("unchecked")

like image 1
Andrei Fierbinteanu Avatar answered Oct 17 '22 13:10

Andrei Fierbinteanu


Thanks to the way java generics where designed this code wont work at all. Generics are only useful for compile time type checking as the classes don't use generic type information at runtime.

Your code will be compiled to this:

 static Object castOrNull(Object obj) {
  try {
   return (Object)obj;//FAIL: this wont do anything
  }
  catch(ClassCastException e) {
   return null;
  }
 }

The cast to Object will never fail, and the compiled code has no access to the generic types present at compile time. Since the cast does not happen the way it should you receive a warning for an unchecked operation.

like image 1
josefx Avatar answered Oct 17 '22 13:10

josefx