javax.measureの紹介

1概要

この記事では、測定単位APIを紹介します。これは、測定値と単位をJavaで表現する** 統一的な方法を提供します。

物理量を含むプログラムを使って作業している間、使用されている単位についての不確実性を取り除く必要があります。計算の誤りを防ぐために、数とその単位の両方を管理することが重要です。

JSR-363 (以前の JSR-275 または javax.measure ライブラリ)を使用すると、開発時間を節約でき、同時にコードが読みやすくなります。

2 Mavenの依存関係

ライブラリを利用するためにMavenの依存関係から始めましょう。

<dependency>
    <groupId>javax.measure</groupId>
    <artifactId>unit-api</artifactId>
    <version>1.0</version>
</dependency>

最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22unit-api%22[Maven Central]にあります。

unit-api プロジェクトには、数量と単位の扱い方を定義する一連のインターフェースが含まれています。例として、 JSR-363 の参照実装( unit-ri )を使用します。

<dependency>
    <groupId>tec.units</groupId>
    <artifactId>unit-ri</artifactId>
    <version>1.0.3</version>
</dependency>

3 APIの検討

水をタンクに貯めたい例を見てみましょう。

従来の実装は次のようになります。

public class WaterTank {
    public void setWaterQuantity(double quantity);
}

ご覧のとおり、上記のコードでは水の量の単位について言及しておらず、 double 型が存在するため正確な計算には適していません。

開発者が予期したものとは異なる測定単位で誤って値を渡すと、計算に重大な誤りが生じる可能性があります。そのようなエラーは、検出および解決が非常に困難です。

  • ** JSR-363 APIは Quantity Unit インターフェースを提供します。これらはこの混乱を解決し、これらの種類のエラーをプログラムの範囲外にします。

3.1. 簡単な例

それでは、私たちの例でこれがどのように役立つのかを調べてみましょう。

前述のように、 JSR-363 には、体積や面積などの定量的なプロパティを表す Quantity インタフェースが含まれています。このライブラリは、最も一般的に使用される数量化可能な属性をモデル化した多数のサブインタフェースを提供しています。例をいくつか示します: Volume Length ElectricCharge Energy Temperature

この例では、 Quantity <Volume> オブジェクトを定義します。

public class WaterTank {
    public void setCapacityMeasure(Quantity<Volume> capacityMeasure);
}

Quantity インターフェースの他に、 Unit インターフェースを使用して、プロパティの測定単位を識別することもできます 。よく使われる単位の定義は、 unit-ri ライブラリにあります。

KELVIN METRE NEWTON CELSIUS

タイプ Quantity <QはQuantity <Q>> を拡張し、単位と値を取得するためのメソッドを持っています: getUnit() getValue()

水量の値を設定する例を見てみましょう。

@Test
public void givenQuantity__whenGetUnitAndConvertValue__thenSuccess() {
    WaterTank waterTank = new WaterTank();
    waterTank.setCapacityMeasure(Quantities.getQuantity(9.2, LITRE));
    assertEquals(LITRE, waterTank.getCapacityMeasure().getUnit());

    Quantity<Volume> waterCapacity = waterTank.getCapacityMeasure();
    double volumeInLitre = waterCapacity.getValue().doubleValue();
    assertEquals(9.2, volumeInLitre, 0.0f);
}

LITRE のこの Volume を他の単位に素早く変換することもできます。

double volumeInMilliLitre = waterCapacity
  .to(MetricPrefix.MILLI(LITRE)).getValue().doubleValue();
assertEquals(9200.0, volumeInMilliLitre, 0.0f);

しかし、水の量を Volume 型ではない別の単位に変換しようとすると、コンパイルエラーになります。

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

3.2. クラスのパラメータ化

次元の一貫性を維持するために、フレームワークは当然総称を利用します。

クラスとインタフェースはそれらの数量型によってパラメータ化され、それはコンパイル時に我々のユニットをチェックさせることを可能にします。コンパイラは、識別できる内容に基づいてエラーまたは警告を出します。

Unit<Length> Kilometer = MetricPrefix.KILO(METRE);
Unit<Length> Centimeter = MetricPrefix.CENTI(LITRE);//compilation error

asType() メソッドを使用して型チェックを回避する可能性は常にあります。

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

数量の種類がわからない場合は、ワイルドカードを使用することもできます。

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

4単位変換

__Unit SystemOfUnits から取得できます。仕様の参照実装は、最も一般的に使用される単位を表す静的定数のセットを提供するインタフェースの Units__実装を含みます。

さらに、まったく新しいカスタムユニットを作成したり、既存のユニットに代数演算を適用してユニットを作成することもできます。

標準単位を使用する利点は、コンバージョンの落とし穴に遭遇しないことです。

KILO(Unit <Q> unit) CENTI(Unit <Q> unit) のように、接頭辞、または MetricPrefix クラスの乗数を使用することもできます。これらはそれぞれ、乗算および10のべき乗で除算するのと同じです。

たとえば、「キロメートル」と「センチメートル」を次のように定義できます。

Unit<Length> Kilometer = MetricPrefix.KILO(METRE);
Unit<Length> Centimeter = MetricPrefix.CENTI(METRE);

欲しいユニットが直接手に入らない場合に使用できます。

4.1. カスタムユニット

いずれにせよ、ユニットのシステムにユニットが存在しない場合は、新しいシンボルを使用して新しいユニットを作成できます。

  • AlternateUnit - 寸法は同じだが異なる新しいユニット

シンボルと自然 ** __ProductUnit - 合理的な力の積として作られた新しい単位

他のユニットの

これらのクラスを使ってカスタムユニットを作成しましょう。圧力に対する AlternateUnit の例:

@Test
public void givenUnit__whenAlternateUnit__ThenGetAlternateUnit() {
    Unit<Pressure> PASCAL = NEWTON.divide(METRE.pow(2))
      .alternate("Pa").asType(Pressure.class);
    assertTrue(SimpleUnitFormat.getInstance().parse("Pa")
      .equals(PASCAL));
}

同様に、 ProductUnit とその変換の例:

@Test
public void givenUnit__whenProduct__ThenGetProductUnit() {
    Unit<Area> squareMetre = METRE.multiply(METRE).asType(Area.class);
    Quantity<Length> line = Quantities.getQuantity(2, METRE);
    assertEquals(line.multiply(line).getUnit(), squareMetre);
}

ここでは、 METRE にそれ自体を掛けて squareMetre 複合単位を作成しました。

次に、ユニットのタイプに対して、フレームワークは UnitConverter クラスも提供します。これは、あるユニットを別のユニットに変換したり、 TransformedUnit という新しい派生ユニットを作成したりするのに役立ちます。

double値の単位をメートルからキロメートルに変える例を見てみましょう。

@Test
public void givenMeters__whenConvertToKilometer__ThenConverted() {
    double distanceInMeters = 50.0;
    UnitConverter metreToKilometre = METRE.getConverterTo(MetricPrefix.KILO(METRE));
    double distanceInKilometers = metreToKilometre.convert(distanceInMeters );
    assertEquals(0.05, distanceInKilometers, 0.00f);
}

数量とそれらの単位との明確な電子通信を容易にするために、ライブラリは UnitFormat インタフェース __、 を提供しています。これはシステム全体のラベルを Units__に関連付けます。

SimpleUnitFormat 実装を使用していくつかのシステムユニットのラベルを確認しましょう。

@Test
public void givenSymbol__WhenCompareToSystemUnit__ThenSuccess() {
    assertTrue(SimpleUnitFormat.getInstance().parse("kW")
      .equals(MetricPrefix.KILO(WATT)));
    assertTrue(SimpleUnitFormat.getInstance().parse("ms")
      .equals(SECOND.divide(1000)));
}

5数量による作業の実行

Quantity インターフェースには、最も一般的な数学演算のためのメソッドが含まれています。これらを使用して、 Quantity オブジェクト間で操作を実行できます。

@Test
public void givenUnits__WhenAdd__ThenSuccess() {
    Quantity<Length> total = Quantities.getQuantity(2, METRE)
      .add(Quantities.getQuantity(3, METRE));
    assertEquals(total.getValue().intValue(), 5);
}

メソッドはまた、それらが操作しているオブジェクトの Units を検証します。たとえば、メートルにリットルを掛けようとすると、コンパイルエラーが発生します。

----//compilation error
Quantity<Length> total = Quantities.getQuantity(2, METRE)
  .add(Quantities.getQuantity(3, LITRE));
----

一方、同じ寸法を持つ単位で表された2つのオブジェクトを追加することができます。

Quantity<Length> totalKm = Quantities.getQuantity(2, METRE)
  .add(Quantities.getQuantity(3, MetricPrefix.KILO(METRE)));
assertEquals(totalKm.getValue().intValue(), 3002);

この例では、メートルとキロメートルの両方の単位が Length ディメンションに対応しているため、それらを追加できます。結果は最初のオブジェクトの単位で表されます。

6. 結論

この記事では、[Measurement APIの単位]が便利な測定モデルを提供することを確認しました。そして、 Quantity Unit の使用法とは別に、いくつかの方法で、1つのユニットを別のユニットに変換することがいかに便利かを見ました。

詳細については、https://github.com/unitsofmeasurement[ここのプロジェクト]をいつでもチェックアウトできます。

そして、いつものように、コード全体はhttps://github.com/eugenp/tutorials/tree/master/libraries[over GitHub]から入手可能です。

前の投稿:Spring Cloudシリーズ - ゲートウェイパターン
次の投稿:Spring Cloudセキュリティ入門