Pengantar javax.measure

1. Ikhtisar

Di artikel ini, kami akan memperkenalkan Unit API Pengukuran - yang menyediakan cara terpadu untuk merepresentasikan ukuran dan unit di Jawa .

Saat bekerja dengan program yang berisi besaran fisik, kita perlu menghilangkan ketidakpastian tentang satuan yang digunakan. Penting bagi kami untuk mengelola angka dan unitnya untuk mencegah kesalahan dalam penghitungan.

JSR-363 (sebelumnya JSR-275 atau javax.measure library) membantu kami menghemat waktu pengembangan, dan pada saat yang sama, membuat kode lebih mudah dibaca.

2. Ketergantungan Maven

Mari kita mulai dengan ketergantungan Maven untuk menarik perpustakaan:

 javax.measure unit-api 1.0  

Versi terbaru dapat ditemukan di Maven Central.

Proyek unit-api berisi sekumpulan antarmuka yang menentukan cara bekerja dengan kuantitas dan unit. Sebagai contoh, kita akan menggunakan implementasi referensi JSR-363 , yaitu unit-ri :

 tec.units unit-ri 1.0.3 

3. Menjelajahi API

Mari kita lihat contoh di mana kita ingin menyimpan air di dalam tangki.

Implementasi lama akan terlihat seperti ini:

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

Seperti yang bisa kita lihat, kode di atas tidak menyebutkan satuan kuantitas air dan tidak cocok untuk penghitungan yang tepat karena adanya tipe ganda .

Jika pengembang keliru mengirimkan nilai dengan satuan ukuran yang berbeda dari yang kami harapkan, hal itu dapat menyebabkan kesalahan serius dalam penghitungan. Kesalahan seperti itu sangat sulit dideteksi dan diselesaikan.

The JSR-363 API memberikan kita dengan Quantity dan Satuan interface , yang menyelesaikan kebingungan ini dan meninggalkan jenis-jenis kesalahan keluar dari ruang lingkup program kami.

3.1. Contoh Sederhana

Sekarang, mari kita jelajahi dan lihat bagaimana ini bisa berguna dalam contoh kita.

Seperti disebutkan sebelumnya, JSR-363 berisi para Kuantitas antarmuka yang merupakan properti kuantitatif seperti volume atau daerah. Pustaka menyediakan banyak sub-antarmuka yang memodelkan atribut terukur yang paling umum digunakan. Beberapa contohnya adalah: Volume , Panjang , Pengisian Listrik , Energi , Suhu .

Kita dapat menentukan objek Kuantitas , yang harus menyimpan jumlah air dalam contoh kita:

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

Selain antarmuka Kuantitas , kita juga dapat menggunakan antarmuka Satuan untuk mengidentifikasi satuan pengukuran properti . Definisi unit yang sering digunakan dapat ditemukan di pustaka unit-ri , seperti: KELVIN , METER , NEWTON , CELSIUS .

Objek berjenis Kuantitasmemiliki metode untuk mengambil unit dan nilai: getUnit () dan getValue () .

Mari kita lihat contoh untuk menetapkan nilai kuantitas air:

@Test public void givenQuantity_whenGetUnitAndConvertValue_thenSuccess() { WaterTank waterTank = new WaterTank(); waterTank.setCapacityMeasure(Quantities.getQuantity(9.2, LITRE)); assertEquals(LITRE, waterTank.getCapacityMeasure().getUnit()); Quantity waterCapacity = waterTank.getCapacityMeasure(); double volumeInLitre = waterCapacity.getValue().doubleValue(); assertEquals(9.2, volumeInLitre, 0.0f); }

Kami juga dapat mengonversi Volume ini dalam LITER ke satuan lain dengan cepat:

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

Tetapi, ketika kami mencoba mengubah jumlah air menjadi unit lain - yang bukan berjenis Volume , kami mendapatkan kesalahan kompilasi:

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

3.2. Parameterisasi Kelas

Untuk menjaga konsistensi dimensi, framework secara alami memanfaatkan obat generik.

Kelas dan antarmuka diberi parameter berdasarkan jenis kuantitasnya, yang memungkinkan unit kami diperiksa pada waktu kompilasi. Kompilator akan memberikan kesalahan atau peringatan berdasarkan apa yang dapat diidentifikasi:

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

Selalu ada kemungkinan melewati pemeriksaan jenis menggunakan metode asType () :

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

Kita juga bisa menggunakan wildcard jika kita tidak yakin dengan jenis kuantitasnya:

Unit kelvinPerSec = KELVIN.divide(SECOND);

4. Konversi Satuan

Unit dapat diambil dari SystemOfUnits . Implementasi referensi spesifikasi berisi implementasi Unit antarmuka yang menyediakan sekumpulan konstanta statis yang mewakili unit yang paling umum digunakan.

Selain itu, kita juga dapat membuat unit kustom baru atau membuat unit dengan menerapkan operasi aljabar pada unit yang sudah ada.

Manfaat menggunakan unit standar adalah kami tidak mengalami kesulitan konversi.

Kita juga bisa menggunakan prefiks, atau pengali dari kelas MetricPrefix , seperti KILO (Satuan satuan) dan CENTI (Satuan satuan) , yang setara dengan mengalikan dan membagi dengan pangkat 10 masing-masing.

Misalnya, kita dapat mendefinisikan "Kilometer" dan "Sentimeter" sebagai:

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

These can be used when a unit we want is not available directly.

4.1. Custom Units

In any case, if a unit doesn't exist in the system of units, we can create new units with new symbols:

  • AlternateUnit – a new unit with the same dimension but different symbol and nature
  • ProductUnit – a new unit created as the product of rational powers of other units

Let's create some custom units using these classes. An example of AlternateUnit for pressure:

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

Similarly, an example of ProductUnit and its conversion:

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

Here, we have created a squareMetre compound unit by multiplying METRE with itself.

Next, to the types of units, the framework also provides a UnitConverter class, which helps us convert one unit to another, or create a new derived unit called TransformedUnit.

Let's see an example to turn the unit of a double value, from meters to kilometers:

@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); }

To facilitate unambiguous electronic communication of quantities with their units, the library provides the UnitFormat interface, which associates system-wide labels with Units.

Let's check the labels of some system units using the SimpleUnitFormat implementation:

@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. Performing Operations With Quantities

The Quantity interface contains methods for the most common mathematical operations: add(), subtract(), multiply(), divide(). Using these, we can perform operations between Quantity objects:

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

The methods also verify the Units of the objects they are operating on. For example, trying to multiply meters with liters will result in a compilation error:

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

On the other hand, two objects expressed in units that have the same dimension can be added:

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

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

Di artikel ini, kami melihat bahwa Unit API Pengukuran memberi kami model pengukuran yang nyaman. Dan, selain penggunaan Kuantitas dan Satuan , kami juga melihat betapa nyamannya mengonversi satu unit ke unit lainnya, dalam beberapa cara.

Untuk informasi lebih lanjut, Anda selalu dapat melihat proyeknya di sini.

Dan, seperti biasa, seluruh kode tersedia di GitHub.