How to avoid an unchecked cast when using unbounded generified static functions in a ternary?

StackOverflow https://stackoverflow.com/questions/22898440

  •  28-06-2023
  •  | 
  •  

Pergunta

I am trying to figure out if there is a way to avoid the unchecked cast in this function (using Java 7):

private static <O> ValueValidator<O> newForAlways(Always valid_orInvalid)  {
   @SuppressWarnings("unchecked")
   ValueValidator<O> vldtr = (ValueValidator<O>)(valid_orInvalid == Always.VALID
      ?  newForAlwaysValid()
      :  newForAlwaysInvalid());
   return  vldtr;
}

Here are the signatures of the two functions being returned:

private static <O> ValueValidator<O> newForAlwaysValid()  {
private static <O> ValueValidator<O> newForAlwaysInvalid()  {

(And here's the Always enum, which is just a boolean substitute:

enum Always {VALID, INVALID;};

)

All three functions have the same return type and contain an unbounded generic. These two questions explain why it happens, although both are about bounded generics:

So even though this works

ValueValidator<Integer> intVldtr = Test.<Integer>newForAlwaysValid();

this doesn't:

private static <O> ValueValidator<O> newForAlways(Always valid_orInvalid)  {
   return  (valid_orInvalid == Always.VALID
      ?  <O>newForAlwaysValid()
      :  <O>newForAlwaysInvalid());
}

C:\java_code\Test.java:15: error: illegal start of expression
      ?  <O>newForAlwaysValid()

...and 8 more similar errors...

And neither does this:

private static <O> ValueValidator<O> newForAlways2(Always valid_orInvalid)  {
   return  (valid_orInvalid == Always.VALID
      ?  newForAlwaysValid()
      :  newForAlwaysInvalid());
}

C:\java_code\Test.java:15: error: incompatible types
          ?  newForAlwaysValid()
          ^
  required: ValueValidator<O>
  found:    ValueValidator<Object>
  where O is a type-variable:
    O extends Object declared in method <O>newForAlways2(Always)

So, to repeat the question: Is there any alternative to the unchecked cast? (I'm using Java 7.)

SSCCE:

public class Test  {
   public static void main(String[] ignored)  {
      ValueValidator<Integer> intVldtr = Test.<Integer>newForAlwaysValid();
      intVldtr = Test.<Integer>newForAlways(Always.VALID);
   }
   private static <O> ValueValidator<O> newForAlways(Always valid_orInvalid)  {
      @SuppressWarnings("unchecked")
      ValueValidator<O> vldtr = (ValueValidator<O>)(valid_orInvalid == Always.VALID
         ?  newForAlwaysValid()
         :  newForAlwaysInvalid());
      return  vldtr;
   }
   private static <O> ValueValidator<O> newForAlwaysValid()  {
      return  (new AlwaysValid<O>());
   }
   private static <O> ValueValidator<O> newForAlwaysInvalid()  {
      return  (new AlwaysInvalid<O>());
   }
}
enum Always {VALID, INVALID;};
abstract class ValueValidator<O>  {
   public abstract boolean isValid(O to_validate);
}
class AlwaysValid<O> extends ValueValidator<O>  {
   public boolean isValid(O to_validate)  {
      return  true;
   }
}
class AlwaysInvalid<O> extends ValueValidator<O>  {
   public boolean isValid(O to_validate)  {
      return  false;
   }
}
Foi útil?

Solução 2

So you already know that there was an issue with generic type argument inferencing with conditional operator in Java 7, which has been fixed in Java 8. Just to fix your issue, you can use explicit type argument.

Well, you already tried to do it, but that was invalid syntax. When you use explicit type argument, you always have to qualify the method invocation with either the object type or class type. So change your method to:

private static <O> ValueValidator<O> newForAlways(Always valid_orInvalid)  {

  ValueValidator<O> vldtr = valid_orInvalid == Always.VALID
     ?  Test.<O>newForAlwaysValid()
     :  Test.<O>newForAlwaysInvalid();
  return  vldtr;
}

Outras dicas

You could just do

ValueValidator<O> vldtr = valid_orInvalid == Always.VALID 
            ? Test.<O>newForAlwaysValid()
            : Test.<O>newForAlwaysInvalid();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top