3

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;
   }
}
Community
  • 1
  • 1
aliteralmind
  • 19,847
  • 17
  • 77
  • 108

2 Answers2

3

You could just do

ValueValidator<O> vldtr = valid_orInvalid == Always.VALID 
            ? Test.<O>newForAlwaysValid()
            : Test.<O>newForAlwaysInvalid();
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
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;
}
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • I do believe this code works in Java 7 as well. You're very explicit about the type of each operand. – Sotirios Delimanolis Apr 06 '14 at 19:04
  • @SotiriosDelimanolis It does? I don't remember. I don't understand the second part of your comment though. – Rohit Jain Apr 06 '14 at 19:05
  • I can't believe it's that simple. Thanks to you both. – aliteralmind Apr 06 '14 at 19:06
  • 1
    By explicitly specifying the type argument for both operands of the `?:` operator, ie. the two method invocations, the compiler will know that type of the expressions is `ValueValidator` for both and there is therefore no confusion. – Sotirios Delimanolis Apr 06 '14 at 19:08
  • When you pass in a generic type into a function this way, the term is "explicit type argument"? – aliteralmind Apr 06 '14 at 19:08
  • 1
    @aliteralmind yes, you are explicitly specifying the generic type argument. Java performs something called "type inference" when it saves you from doing this most of the time. Like Rohit said, in Java 7 it is unable to do so in this case and this has been fixed in Java 8. – Benjamin Gruenbaum Apr 06 '14 at 19:11