As a minimum, the unit format recognizes the 20
SI prefixes used to form decimal multiples and submultiples of
SI units, as shown in Listing 11.
Listing 11. Using
Unit.valueOf("m°C").equals(SI.MILLI(SI.CELSIUS)) // True Unit.valueOf("kW").equals(SI.KILO(SI.WATT)) // True Unit.valueOf("ft").equals(SI.METER.multiply(3048).divide(10000)) // True Unit.valueOf("ft").equals(SI.METER.multiply(0.3048)) // True!
In Listing 11, the last assertion is true, which might be a little puzzling, given that the
double 0.3048 is about 0.3048000000000000154 (when represented using 19 digits), and the foot international unit (ft) has been standardized to be exactly 3048/10000 meters. The assertion is true because two converters are considered equals if their quotient is the identity converter. The concatenation of a rational converter and a multiply converter (or its inverse) is a multiply converter (inexact) for which equality comparison is not strict to account for numeric errors.
The unit format recognizes product units. The following strings, for example, all represent the same meter per square second units:
As I mentioned earlier, compound units can be used to format
Measure in a canonical (unique) form using integer-value coefficients, as shown in Listing 12.
Listing 12. Compound units
Unit<Duration> HOUR_MINUTE_SECOND = HOUR.compound(MINUTE).compound(SECOND); Measure<Integer, Duration> d = Measure.valueOf(12345, SECOND); System.out.println(d.to(HOUR_MINUTE_SECOND)); >> 3h25min45s
A question often asked is why
Measurable are parameterized by the quantity type and not some dimension type.
The first easy answer is that there is no such thing as a "dimension type." You'll find dimension instances that can be operated upon (product/quotient of dimensions), but class parameterization works only with classes, not instances. Also, using a dimension class for parameterization would lead to the following problems:
- Dimensions change with the model. For example, the dimension of the watt unit is [L]²·[M]/[T]³ in the standard model, but it becomes [M]/[T] in the relativistic model. JSR 275 supports custom models for which the number of independent dimensions can be decreased (from seven in the standard model) or increased. (You could add an angular dimension or a monetary dimension, for example.) Modern physics often works with natural units, for which the number of independent dimensions is reduced to zero (all quantities are dimensionless)!
- Units can have the same dimension and still apply to different quantities. For example both torque and energy have a dimension of [L]²·[M]/[T]² in the standard model. Nevertheless it is convenient and safer to consider them as two different quantities with their own units. Other examples are sea water salinity (PSS-78), which is some kind of concentration, and angles, which are all dimensionless but still convenient to treat as different kinds of quantities. A unit's dimension can be easily retrieved using the
Unit.getDimension()method. For example:
[L]²·[M]/[T]². But the physical "type" of a unit can be identified only by its standard units. Consider the
REVOLUTION.divide(MINUTE)unit. Its dimension is
1/[T]-- basically the same dimension as frequency. But
rad/s, which unequivocally identifies the unit as an angular-velocity unit.
See the Resources section to learn more about dimensional analysis.
A case study: The monetary system
The monetary system is out of JSR 275's scope, but it illustrates how easily the framework can be extended to nonphysical quantities. Such extension can be valuable in the sense that it not only leverages the specification's capabilities (formatting, conversions, and so on) but it compounds its usefulness as well. For example, you can now work with hybrid quantities such as dollar per gallon (gas price) or Euro per square meter (material price) or Yen per kilogram (food price). Figure 3 shows (in green) the new classes and how they attach to the framework.
There's no need to subclass
Measurable. The statements in Listing 13 are supported without further customizations.
Listing 13. Monetary-system integration
Measure<Double, ?> gazPrice = Measure.valueOf(1.2, EUR.divide(LITRE)); // 1.2 €/L System.out.println(gazPrice.getDimension()); >> [$]/[L]³ Measure<Double, Money> wallet = Measure.valueOf(13.2, EUR); Unit<Money> DOLLAR_CENT = USD.compound(CENTI(USD)); System.out.println(wallet.to(DOLLAR_CENT)); >> 18$10¢
Just as parameterization enhanced the Java Collections Framework, the Measures and Units API adds a new dimension to Java primitive types. Whether or not JSR 275 will be included in the Java 7 platform has not yet been decided. We can certainly hope so, because it provides a common framework allowing unit-safe integration of higher-level libraries (such as JSR 310: Date and Time API). In the meantime, you can download the reference implementation from the JScience project.
Thanks to Martin Desruisseaux, who wrote the first draft of the specification, and to the expert group for its valuable input and feedback.
Learn more about this topic
- The latest draft of the JSR 275 specification is available under "Document & files" from the JSR 275 project area on java.net.
- The JSR 275 reference implementation can be downloaded from the JScience Project either with the full JScience distribution or separately.
- The Unified Code for Units of Measure (UCUM) is a code system intended to include all units of measurement used in international science, engineering, and business.
- Wikipedia explains dimensional analysis and natural units.
- Visit the JavaWorld Java Standard Edition research center for more articles about Java programming with units and measures.
- Also check out the JavaWorld developer forums for discussions and Q&A related to physical measurements in Java applications.