DJUNITS - Delft Java UNIT System version 3.00  

Adding a unit instance to an existing unit

DJUNITS defines a sizable number of instantiated units that are ready to use, but not all. Therefore, extra instantiated units can be easily added. Suppose, that a user would like to add a Furlong (an imperial length unit of one eighth of a mile, or 660 feet), a Fortnight (a duration unit of 14 days), and a speed unit that indicates the speed in Furlongs per Fortnight. All three are relative units. Suppose that the user wants to make these three units available as public static constants in a utility class. The code to do so looks as follows:
public static LengthUnit FURLONG = new LengthUnit("Furlong", "fr", 
   UnitSystem.IMPERIAL, LengthUnit.FOOT, 660);
public static DurationUnit FORTNIGHT = new DurationUnit("Fortnight", "fn", 
   UnitSystem.OTHER, DurationUnit.DAY, 14);
public static SpeedUnit FURLONGS_PER_FORTNIGHT = new SpeedUnit(
   FURLONG, FORTNIGHT, "Furlongs per Fortnight", "fr/fn", UnitSystem.OTHER);
The first two definitions use a constructor that define a unit with respect to another unit using a factor, as the LengthUnit has been defined with a LinearScale and as it has a constructor with a factor. It is no problem that the Furlong is defined with respect to a Foot; the factor to the SI unit will be calculated as part of the constructor. The last definition uses the speed unit constructor that takes a length unit and a duration unit, and constructs a speed unit from this. Again, the factor to map Furlongs per Fortnight to and from the SI unit meters per second, will be automatically calculated. These units can now be used in any piece of code, e.g.:
Length fr1000 = new Length(1000.0, FURLONG);
Duration twoWeeks = new Duration(1.0, FORTNIGHT);
Speed speed = fr1000.divideBy(twoWeeks);
System.out.println(speed);
System.out.println(speed.toString(FURLONGS_PER_FORTNIGHT));
The program will print the following output:
0.16630952m/s
1000.00000fr/fn

Defining a completely new Unit

Of course it is also possible to define a completely new unit from scratch. The instructions below show how to create a new unit.

Every unit extends Unit with the defined unit as its generic; this ensures that the generic unit can do proper housekeeping, also for the units that are user-defined. Many units have a natural zero value and linear scales. These units extend the LinearUnit that provides a number of constructors with an easy-to-use factor to create a linear scale with respect to the standard (SI) unit. Jerk is a relative unit. The header of the user-defined unit for jerk, the rate of change of acceleration (meter per second3) is therefore:

public class JerkUnit extends LinearUnit<JerkUnit>

Often, the unit(s) on which the new unit is based are stored as part of the unit. In this case, a length unit and a duration unit. Furthermore, several standard units are defined, among which the SI constant, if possible:

private final LengthUnit lengthUnit;
private final DurationUnit durationUnit;
public static final JerkUnit SI;
public static final JerkUnit M_PER_S3;
public static final JerkUnit CM_PER_S3;
public static final JerkUnit FT_PER_S3;
public static final JerkUnit JERK;

We usually define the constants in a static code block, to ensure the order in which the static units are defined. If the units are defined as part of the public static definitions, one cannot guarantee that the SI unit will be defined before other units that are defined on the basis of the SI unit, for instance. The static code block (also called the class constructor or <clinit>) is executed only once when the class is loaded for the first time. Also see the different ways that the constructors are used. The FT_PER_S3 is defined on the basis of the LengthUnit FOOT, while the JERK (also a [ft/s3]) is defined respective to the SI unit with a factor.

static 
{
  SI = new JerkUnit(LengthUnit.METER, DurationUnit.SECOND, 
    "meter per cubed second", "m/s^3", UnitSystem.SI_BASE); 
  M_PER_S3 = SI;
  CM_PER_S3 = new JerkUnit(LengthUnit.CENTIMETER, DurationUnit.SECOND, 
    "centimeter per cubed second", "cm/s^3", UnitSystem.SI_BASE); 
  FT_PER_S3 = new JerkUnit(LengthUnit.FOOT, DurationUnit.SECOND, 
    "foot per cubed second", "ft/s^3", UnitSystem.IMPERIAL);
  JERK = new JerkUnit("jerk", "jerk", UnitSystem.OTHER, SI, 0.3048);
}

The constructors are pretty straightforward; they define the unit either on the basis of the SI unit, or on the basis of a length unit and a duration unit (the factor of which is cubed):

public JerkUnit(final LengthUnit lengthUnit, final DurationUnit durationUnit, final String name,
         final String abbreviation, final UnitSystem unitSystem)
{
  super(name, abbreviation, unitSystem, SI, lengthUnit.getConversionFactorToStandardUnit()
          / Math.pow(durationUnit.getConversionFactorToStandardUnit(), 3.0), false);
  this.lengthUnit = lengthUnit;
  this.durationUnit = durationUnit;
}

 public JerkUnit(final String name, final String abbreviation, final UnitSystem unitSystem,
        final JerkUnit referenceUnit, final double conversionFactorToReferenceUnit)
{
  super(name, abbreviation, unitSystem, referenceUnit, conversionFactorToReferenceUnit,
	      false);
  this.lengthUnit = referenceUnit.getLengthUnit();
  this.durationUnit = referenceUnit.getDurationUnit();
}

The "false" as the last argument to the super-constructor of the Unit indicates that this is not a standard unit. This means it is not localized, nor looked up in the "localeunit.properties" file. Instead, the strings given as "name" and "abbreviation" are used when printing the unit. In case you add the units to the localization files, use the key to the items in the localization file as name and abbreviation. The Unit class will then look up the (localized) strings for the name and abbreviation in the corresponding language locale files.

Finally, add the methods that are prescribed by Unit, and allow the user of the class to retrieve the length unit and duration unit on which this class has been based (if necessary):

public final LengthUnit getLengthUnit() { return this.lengthUnit; }
public final DurationUnit getDurationUnit() { return this.durationUnit; }

@Override
public final JerkUnit getStandardUnit() { return SI; }

@Override
public final String getSICoefficientsString() { return "m/s3"; }

The getSICoefficientsString() method should return a String with SI coefficients in a fixed order: kg - m - s - A - K - cd - mol. If necessary, one divider can be used; in that case the coefficients should only appear in the numerator or the denominator, but not in both. For the numerator and the denominator, the order given should be used. Coefficients are indicated as a positive number. So, Volts have an SI unit of: kgm2/s3A. If there is only a denominator, use 1/ as the start of the string. Frequency has 1/s as the SI coefficient string.

Note: the amount of one Jerk is a foot per cubed second, and comes from several sources, e.g., https://www.unc.edu/~rowlett/units/dictJ.html.
Note: the above code is for instructional purposes and does not include documentation and JavaDoc. Never write code without it!