Class parameterization is arguably the single most important enhancement to the Java platform since its infancy. The parameterized collection framework (
java.util.*) demonstrates only a small fragment of what can be done through parameterization. The JScience project has pushed the envelope even further by taking advantage of parameterization in new areas such as mathematical structures (
Group), vectors/matrices and functions.
Parameterization has many advantages, not least being a "zero-cost at run time" because all the checks are done at compile time. JSR 275 takes advantage of class parameterization to ensure dimension consistency. As Listing 5 shows, classes such as
Unit are parameterized by their quantity type (such as
Length). The dimensions of a unit (or measure) can be retrieved from the unit itself (at run time) of inferred from its quantity type (at compile time).
Listing 5. Parameterization for dimension consistency
Unit<length> inch = CENTI(METER).times(2.54); // OK. Unit<length> inch = CENTI(LITER).times(2.54); // Compile error. Measurable<Duration> d = Measure.valueOf(2, MINUTE); // OK. Measurable<Duration> d = Measure.valueOf(2, WATT); // Compile Error. long milliseconds = d.longValue(MILLI(SECOND)); // OK. long milliseconds = d.longValue(MILLI(HERTZ)); // Compile error.
When the compiler can't ensure commensurability, it issues a warning that can easily be removed through an explicit run-time check of the dimensions or by using the
? wildcard parameterized type (see Listing 6).
Listing 6. Compiler warnings and how to remove them
// Compiler Warnings Unit<Acceleration> mps2 = Unit.valueOf("m/s²"); // Compiler Warning. Unit<Power> WATT = JOULE.divide(SECOND); // Compiler Warning. // Adding run-time check of dimension consistency removes the warning. Unit<Acceleration> mps2 = Unit.valueOf("m/s²").asType(Acceleration.class); Unit<Power> WATT = JOULE.divide(SECOND).asType(Power.class); // Use wildcard parameterized type (no warning and no check). Unit<?> kelvinPerSec = KELVIN.divide(SECOND);
Units and units conversions
Units can be retrieved from constants held by various
SystemOfUnits subclasses, such as
SI (holding the "Système International d'Unités" standard units) or
NonSI (holding nonstandard but common units). Custom systems of units can be created, and units can belong to several system of units. For example, the imperial system would contain many of the
NonSI units. (You can use the
SystemOfUnits.getUnits() member method to list all the units held by a system.)
By using predefined units, users avoid many conversion pitfalls. For example, the dry gallon is different from the liquid gallon, which is different in the United States and in the United Kingdom. Differentiation can be done either through
SystemOfUnits (an imperial system would contain the U.K. units exclusively) or through distinct names such as
DAY_CALENDAR, which differentiate between the day corresponding to the rotation of the Earth (23 hours, 56 minutes, 4.09 seconds) and the 24-hour calendar day. All conversion factors have been established from the latest Bureau International des Poids et Mesures (BIPM) standard.
If a unit does not exist in the
NonSI system of units, you can create new units by applying algebraic operations on existing units. Table 1 shows the operations supported on unit instances.
Table 1. Units operations
|Result with same dimension||Result with different dimension|
|Binary operations:||Binary operations:|