Pragmatic Programmer Issues

Conversion and Promotions from Java Specification (ch5)

There was a long time from java specification chapter four review. I think that one of the main reason is that chapter five is boring. Let’s start with it.

The best description in in JavaSpec-ch5 introduction which goes like this: Every expression has a type that can be deduced, it is possible to write an expression where the type is not appropriate, in some cases this lead to error at compile time, in other cases the context is able to accept a type.

Today we managed other cases 😉

  • Conversion from type S to type T allows an expression of type S to be treated at compile time as if it had type T instead. Note : sometimes additional action at runtime are made.
  • Conversion Categories:
    • Identity conversions
    • Widening primitive conversions
    • Narrowing primitive conversions
    • Widening reference conversions
    • Narrowing reference conversions
    • Boxing conversions
    • Unboxing conversions
    • Unchecked conversions
    • Capture conversions
    • String conversions
    • Value set conversions
  • There are five conversion contexts:
    • Assignment conversion : can cause OutOfMemoryError, NullPointerException, ClassCastException
    • Method invocation conversion : can cause OutOfMemoryError, NullPointerException, ClassCastException
    • Casting conversion : certain casts ay cause an exception at runtime.
    • String conversion : any type can be converted to type String
    • Numeric promotion : brings operands to common type so that an operation can be performed.
  • Identity conversion :: Conversion from any type to the same type is permitted for any type ;). This implies that we can include redundant cast operators.
  • Widening primitive conversion :: we can convert
    • byte to short, int, long, float, double
    • short to int, long, float, double
    • char to int, long, float, double
    • int to long, float, double
    • long to float, double
    • float to double
    • widening conversion never result in a runtime exception
    • strictfp preserve the numeric value, not strictfp may lose information
    • NOTE : conversion from int or long to float, or long to double may result in loss of precision !!!int to float loss of precision
  • Narrowing primitive conversion
    • short to byte, char
    • char to byte, short
    • int to byte, short, char
    • long to byte, short, char, int
    • float to byte, short, char, int, long
    • double to byte short, char, int long, float
    • narrowing discards n lowest order bits and this may cause the sign is differ from the sign of the input
    • conversion from floating-point number to integral takes two steps, first step convert to long for long and int for others
      • for NaN it 0
      • if rounded value can be represented as long or int than this is this value
      • otherwise the value is too small than it is the smallest representative of the type int or long
      • or the vale is too large than it is the largest representative of the type int or long
      • in second step for int or long we return value, for others we make another narrowing conversion.
    • Narrowing never result in runtime exception
    • Narrowing examples
  • Widening and Narrowing Primitive Conversion :: the special case byte to char converting, first we wide byte to int and than we narrow int to char.
  • Widening Reference Conversion :: Widening exists from any type S to T if S is T’s subtype, never throw an exception.
  • Narrowing Reference conversion :: such conversion require a test at runtime if actual reference is ok, and if not ClassCastException is thrown
    • any S to any T, when S is supertype of T.
    • any class C to any non-parameterized interface K, C is not final and does NOT implement K.
    • any interface J to not final non-parameterized class C
    • from Cloneable or Serializable to array type T[]
    • any interface J to any non-parameterized interface K, J is not subinterface of K
    • any S[] to T[] S and T are reference type and there is narrowing conversion from S to T
  • Boxing conversion ::
    • boolean (p) to Boolean (r) => p == r.booleanValue() (byte, char, short, int, long are analogous)
    • float if p is non NaN than conversion is analogous as boolean, if it is NaN than it is converted to r such as r.isNaN() evaluates to true. (the same to double)
    • if p is value of any other type, boxing conversion is the same as identity conversion.
    • NOTE : for boolean (true false) and byte, a char in range \u0000 to \u007f and int, short number between -128 and 127 all boxed references ARE THE SAME !!!. For other values do NOT make any assumptions about the identity of boxed values
    • boxing conversion may result in an OutOfMemoryError
  • Unboxing conversion
    • Boolean (r) to byte returns r.booleanValue (analogous for Byte, Character, Short, Integer, Long, Float, Double)
    • for null throws NullPointerException
  • Unchecked conversion :: it is conversion from raw type G to any parameterized type of G<T1, …Tn> and it rise compile time warning.
  • Capture conversion :: never need a special action at runtime therefore never thrown an exception. Designed to make wildcards more useful.
  • String conversion :: all types are convertable to String, even null type !!!.
  • Value Set conversion :: is the process of mapping a floating-point value from one value to another without changing its type. Which means that when we assign float or double values there can be some lose of precision.
  • Assignment Context : occurs when the value of an expression is assigned to a variable.
    • For raw type the chain of conversions may NOT contain two parameterized types that are not in subtype relation (e.g. Integer, Comparable<Integer>, Comparable, Comparable<String> is illegal).
    • OutOfMemoryError (boxing conversion), ClassCastException (heap pollution), NullPointerException (unboxing null reference) may be thrown.
    • Thanks to narrowing we can write byte b = 42;
    • Some interesting facts:
    • assigment context example
  • Method Context : is applied to each argument value in the method or constructor invocation. It the same as Assignment Context with one exception: this context do not include the implicit narrowing of integer constants which is part of assignment, see the example:
  • method context example
  • String Context : is applied only to binary + operator when one of the arguments is String ( it will be covered in chapter 15)
  • Casting Context: is applied to the operand of cast operator, the type must be converted to the type explicitly named by cast operator.
    • Boxing and unboxing allows casting between primitive types and reference types.
    • Remaining cases involves casting between reference types.
    • cast from S to T is statically known to be correct if S is T’s subclass.
    • In spec there is more than 30 detailed rules for casting legality, I will try show this on examples
    • Cast Context examples
  • Numeric Context: is applied to operands of arithmetic operator, there are two kind of numeric promotion
    • Unary numeric promotion : is preformed when:
      • Each dimension expression in an array creation
      • Index expression in an array access
      • operand of unary plus (+), minus (-), bitwise (~) operator
      • each operand !!! separately of >>, >>> and <<, note that long shift (right operand) does not promote the value being shifted (left operand) to long.
    • Binary numeric promotion: the pair of operands are converted with respect to this algorithm:
      1. If any operands is a reference type, unboxing conversion is performed
      2. next we have type hierarchy (double -> float -> long -> int) and we perform conversion to the highest of existing type operand.
      • operators: *, /, %, +, -, <, <=, >, >=, ==, !=, &, ^, |, in certain cases ?:
    • Examples
    • numeric context examples

Categories