Pengenalan kepada javax.measure

1. Gambaran keseluruhan

Dalam artikel ini, kami akan memperkenalkan Unit Pengukuran API - yang menyediakan cara terpadu untuk mewakili ukuran dan unit di Java .

Semasa bekerja dengan program yang mengandungi kuantiti fizikal, kita perlu menghilangkan ketidakpastian mengenai unit yang digunakan. Kita mesti menguruskan nombor dan unitnya untuk mengelakkan kesilapan dalam pengiraan.

JSR-363 (sebelumnya JSR-275 atau javax.measure library) membantu kita menjimatkan masa pembangunan, dan pada masa yang sama, menjadikan kod lebih mudah dibaca.

2. Pergantungan Maven

Mari kita mulakan dengan ketergantungan Maven untuk menarik di perpustakaan:

 javax.measure unit-api 1.0  

Versi terbaru boleh didapati di Maven Central.

Projek unit-api mengandungi satu set antara muka yang menentukan cara bekerja dengan kuantiti dan unit. Sebagai contoh, kami akan menggunakan pelaksanaan rujukan JSR-363 , yang merupakan unit-ri :

 tec.units unit-ri 1.0.3 

3. Meneroka API

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

Pelaksanaan warisan akan kelihatan seperti ini:

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

Seperti yang kita lihat, kod di atas tidak menyebutkan satuan kuantiti air dan tidak sesuai untuk pengiraan yang tepat kerana adanya jenis ganda .

Sekiranya pembangun secara salah melafazkan nilai dengan unit ukuran yang berbeza daripada yang kami harapkan, ini dapat menyebabkan kesalahan serius dalam pengiraan. Kesalahan seperti ini sangat sukar untuk dikesan dan diselesaikan.

The JSR-363 API menyediakan kami dengan Kuantiti dan Unit antara muka , yang menyelesaikan kekeliruan ini dan meninggalkan kedua-jenis kesilapan di luar skop program kita.

3.1. Contoh Ringkas

Sekarang, mari kita terokai dan melihat bagaimana ini boleh berguna dalam contoh kita.

Seperti yang dinyatakan sebelum ini, JSR-363 mengandungi yang Kuantiti antara muka yang mewakili harta kuantitatif seperti kelantangan atau kawasan. Perpustakaan menyediakan banyak sub-antaramuka yang memodelkan atribut kuantitatif yang paling biasa digunakan. Beberapa contoh adalah: Isipadu , Panjang , Caj Elektrik , Tenaga , Suhu .

Kita boleh menentukan objek Kuantiti , yang seharusnya menyimpan kuantiti air dalam contoh kita:

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

Selain antara muka Quantity , kita juga dapat menggunakan antara muka Unit untuk mengenal pasti unit ukuran untuk harta tanah . Definisi untuk unit yang sering digunakan boleh didapati di perpustakaan unit-ri , seperti: KELVIN , METER , NEWTON , CELSIUS .

Objek jenis Kuantitimempunyai kaedah untuk mendapatkan semula unit dan nilai: getUnit () dan getValue () .

Mari lihat contoh untuk menetapkan nilai kuantiti 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 boleh menukar Volume ini dalam LITER ke unit lain dengan cepat:

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

Tetapi, apabila kita cuba menukar jumlah air menjadi unit lain - yang bukan dari jenis Volume , kita mendapat ralat penyusunan:

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

3.2. Parameterisasi Kelas

Untuk mengekalkan konsistensi dimensi, kerangka kerja secara semula jadi memanfaatkan generik.

Kelas dan antara muka di parameter berdasarkan jenis kuantiti mereka, yang memungkinkan untuk memeriksa unit kami pada waktu kompilasi. Penyusun akan memberikan ralat atau amaran berdasarkan apa yang dapat dikenalpasti:

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

Selalu ada kemungkinan untuk melewati pemeriksaan jenis menggunakan kaedah asType () :

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

Kami juga boleh menggunakan wildcard jika kami tidak pasti jenis kuantiti:

Unit kelvinPerSec = KELVIN.divide(SECOND);

4. Penukaran Unit

Unit dapat diambil dari SystemOfUnits . Pelaksanaan rujukan spesifikasi berisi pelaksanaan Unit antara muka yang menyediakan satu set pemalar statik yang mewakili unit yang paling sering digunakan.

Selain itu, kita juga dapat membuat unit khusus yang baru atau membuat unit dengan menerapkan operasi algebra pada unit yang ada.

Manfaat menggunakan unit piawai adalah kita tidak mengalami masalah penukaran.

Kita juga boleh menggunakan awalan, atau pengganda dari kelas MetricPrefix , seperti KILO (Unit unit) dan CENTI (Unit unit) , yang setara dengan darab dan bahagi dengan kekuatan masing-masing 10.

Sebagai contoh, kita dapat menentukan "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

Dalam artikel ini, kami melihat bahawa Unit Pengukuran API memberi kami model pengukuran yang mudah. Selain penggunaan Kuantiti dan Unit , kami juga melihat betapa senangnya menukar satu unit ke unit lain, dengan beberapa cara.

Untuk maklumat lebih lanjut, anda boleh melihat projeknya di sini.

Dan, seperti biasa, keseluruhan kod tersedia di GitHub.