Introduction to javax.measure

I just announced the new Spring 5 modules in REST With Spring:

1. Overview

In this article, we’ll introduce the Units of Measurement API – which provides a unified way of representing measures and units in Java.

While working with a program containing physical quantities, we need to remove the uncertainty about units used. It’s essential that we manage both the number and its unit to prevent errors in calculations.

JSR-363 (formerly JSR-275 or javax.measure library) helps us save the development time, and at the same time, makes the code more readable.

3. Exploring the API

As we can see, the above code does not mention the unit of quantity of water and is not suitable for precise calculations because of the presence of the double type.

If a developer mistakenly passes the value with a different unit of measure than the one we’re expecting, it can lead to serious errors in calculations. Such errors are very hard to detect and resolve.

The JSR-363 API provides us with the Quantity and Unit interfaces, which resolve this confusion and leave these kinds of errors out of our program’s scope.

3.1. Simple Example

Now, let’s explore and see how this can be useful in our example.

As mentioned earlier, JSR-363 contains the Quantity interface which represents a quantitative property such as volume or area. The library provides numerous sub-interfaces that model the most commonly used quantifiable attributes. Some examples are: Volume, Length, ElectricCharge, Energy, Temperature.

We can define the Quantity<Volume> object, which should store the quantity of water in our example:

Besides the Quantity interface, we can also use the Unit interface to identify the unit of measurement for a property. Definitions for often used units can be found in the unit-ri library, such as: KELVIN, METRE, NEWTON, CELSIUS.

An object of type Quantity<Q extends Quantity<Q>> has methods for retrieving the unit and value: getUnit() and getValue().

But, when we try to convert the amount of water into another unit – which is not of type Volume, we get a compilation error:

// compilation error
waterCapacity.to(MetricPrefix.MILLI(KILOGRAM));

3.2. Class Parameterization

To maintain the dimension consistency, the framework naturally takes advantage of generics.

Classes and interfaces are parameterized by their quantity type, which makes it possible to have our units checked at compile time. The compiler will give an error or warning based on what it can identify:

There’s always a possibility of bypassing the type check using the asType() method:

Unit<Length> inch = CENTI(METER).times(2.54).asType(Length.class);

We can also use a wildcard if we are not sure of the type of quantity:

Unit<?> kelvinPerSec = KELVIN.divide(SECOND);

4. Unit Conversion

Units can be retrieved from SystemOfUnits. The reference implementation of the specification contains the Units implementation of the interface which provides a set of static constants that represent the most commonly used units.

In addition, we can also create an entirely new custom unit or create a unit by applying algebraic operations on existing units.

The benefit of using a standard unit is that we don’t run into the conversion pitfalls.

We can also use prefixes, or multipliers from the MetricPrefix class, like KILO(Unit<Q> unit) and CENTI(Unit<Q> unit), which are equivalent to multiply and divide by a power of 10 respectively.

In this example, both meter and kilometer units correspond to the Length dimension so they can be added. The result is expressed in the unit of the first object.

6. Conclusion

In this article, we saw that Units of Measurement API gives us a convenient measurement model. And, apart from the usage of Quantity and Unit, we also saw how convenient it is to convert one unit to another, in a number of ways.