Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In this noncompliant code example, the programmer expects that both print statements will print the value of alpha as a charA:

Code Block
bgColor#FFCCCC
public class Expr {
  public static void main(String[] args) {
    char alpha = 'A';
    int i = 0;
    // Other code. Value of i may change 
    boolean trueExp = true; // Some expression that evaluates to true
    System.out.print(trueExp ? alpha : 0); // prints A
    System.out.print(trueExp ? alpha : i); // prints 65
  }
}

...

This compliant solution uses identical types for the second and third operands of each conditional expression; the explicit casts specify the type expected by the programmer.:

Code Block
bgColor#ccccff
public class Expr {
  public static void main(String[] args) {
    char alpha = 'A';
    int i = 0;
    boolean trueExp = true; // Some expression that evaluates to true
    System.out.print(trueExp ? alpha : ((char) 0)); // prints A
    // Deliberate narrowing cast of i; possible truncation OK
    System.out.print(trueExp ? alpha : ((char) i)); // prints A
  }
}

...

This noncompliant code example prints 100 as the size of the HashSet rather than the expected result (some value between 0 and 50):

Code Block
bgColor#FFCCCC
public class ShortSet {
  public static void main(String[] args) {
    HashSet<Short> s = new HashSet<Short>();
    for (short i = 0; i < 100; i++) {
      s.add(i);
      // Cast of i-1 is safe, because value is always representable
      Short workingVal = (short) (i-1);
      // ... other code may update workingVal

      s.remove(((i % 2) == 1) ? i-1 : workingVal);
    }
    System.out.println(s.size());
  }
}

...

This compliant solution casts the second operand to type short, then explicitly invokes the Short.valueOf() method to create a Short instance whose value is i-1:

Code Block
bgColor#ccccff
public class ShortSet {
  public static void main(String[] args) {
    HashSet<Short> s = new HashSet<Short>();
    for (short i = 0; i < 100; i++) {
      s.add(i);
      // Cast of i-1 is safe, because value is always representable
      Short workingVal = (short) (i-1);
      // ... other code may update workingVal

      // Cast of i-1 is safe, because value is always representable
      s.remove(((i % 2) == 1) ? Short.valueOf((short) (i-1)) : workingVal);
    }
    System.out.println(s.size());
  }
}

...

Automated detection of condition expressions whose second and third operands are of different types is straightforward.

Bibliography

[Bloch 2005a2005]

Puzzle 8, "Dos Equis"

[Findbugs 2008]

"Bx: Primitive Value Is Unboxed and Coerced for Ternary Operator"

[JLS 2011]

§15.25, "Conditional Operator ? :"

...