Enum TimeUnit Java Sangat Berguna

Meskipun merupakan bagian dari paket java.util.concurrent, enum TimeUnit berguna dalam banyak konteks di luar konkurensi. Dalam posting ini, saya melihat bagaimana TimeUnitenum dapat digunakan bahkan dalam kode yang tidak secara langsung berhubungan dengan fungsionalitas bersamaan sebelum memeriksa bagaimana enum ini adalah contoh dari banyak konsep yang lebih luas dalam pengembangan Java.

Sebagian besar dari kita mungkin telah melihat (atau mengimplementasikan, tetapi kita akan menyalahkan pengembang lain untuk itu sekarang) kode seperti yang ditampilkan dalam daftar kode berikutnya. Dalam daftar kode ini, jumlah milidetik yang disediakan diubah menjadi seluruh jumlah hari dengan membaginya dengan angka hardcode tunggal yang ditentukan sebelumnya (86400000, jumlah milidetik dalam satu hari).

 /** * Convert provided number of milliseconds into number of days. * * @param numberMilliseconds Number of milliseconds to be converted into days. * @return Number of days corresponding to number of provided milliseconds. */ private static long convertMilliSecondsToDaysViaSingleMagicNumber(final long numberMilliseconds) { // 86400000 = 86400 seconds in a day multipled by 1000 ms per second return numberMilliseconds / 86400000; } 

Ada beberapa masalah dengan pendekatan yang diambil oleh daftar kode di atas. Masalah yang paling jelas mungkin adalah penggunaan angka ajaib 86400000. Meskipun kebanyakan dari kita mengenali 86400 sebagai jumlah detik dalam sehari, ini mungkin tidak terlihat jelas bagi semua orang dan kemudian ada masalah 1000 kali lebih besar dari angka itu . Komentar dalam daftar kode membantu menjelaskan arti yang mendasari angka-angka tersebut, tetapi bukankah akan menyenangkan jika kode tersebut berbicara lebih jelas untuk dirinya sendiri?

Daftar kode berikutnya menunjukkan sedikit peningkatan yang bisa diperdebatkan. Daripada menggunakan satu nomor hard-coded, digunakan nomor hard-code individual yang lebih mudah dibaca karena terpisah. Seorang pembaca kode memiliki kesempatan yang lebih baik untuk melihat bagaimana nomor itu dibuat.

 /** * Convert provided number of milliseconds into number of days. * * @param numberMilliseconds Number of milliseconds to be converted into days. * @return Number of days corresponding to number of provided milliseconds. */ private static long convertMilliSecondsToDaysViaMoreExplanatoryMagicNumbers(final long numberMilliseconds) { // 60 seconds in minute, 60 minutes in hour, 24 hours in day, and // one thousand milliseconds in a second return numberMilliseconds / (60 * 60 * 24 * 1000); } 

Meskipun nomor individu dapat mempermudah untuk melihat apa yang terjadi dalam konversi, komentar tersebut mungkin masih berguna untuk memastikan bahwa fungsi yang tepat dipahami dengan baik. Angka ajaib juga masih terlibat dan sebagian besar alat analisis kode akan melaporkan masalah dengan penggunaannya. Contoh kode berikutnya mencoba menangani masalah angka ajaib.

 private final static int NUMBER_MILLISECONDS_IN_SECOND = 1000; private final static int NUMBER_SECONDS_IN_MINUTE = 60; private final static int NUMBER_MINUTES_IN_HOUR = 60; private final static int NUMBER_SECONDS_IN_HOUR = NUMBER_SECONDS_IN_MINUTE * NUMBER_MINUTES_IN_HOUR; private final static int NUMBER_HOURS_IN_DAY = 24; private final static int NUMBER_MINUTES_IN_DAY = NUMBER_HOURS_IN_DAY * NUMBER_MINUTES_IN_HOUR; private final static int NUMBER_SECONDS_IN_DAY = NUMBER_HOURS_IN_DAY * NUMBER_SECONDS_IN_HOUR; private final static int NUMBER_MILLISECONDS_IN_DAY = NUMBER_SECONDS_IN_DAY * NUMBER_MILLISECONDS_IN_SECOND; /** * Convert provided number of milliseconds into number of days. * * @param numberMilliseconds Number of milliseconds to be converted into days. * @return Number of days corresponding to number of provided milliseconds. */ private static long convertMilliSecondsToDaysViaDefinedConstant(final long numberMilliseconds) { return numberMilliseconds / NUMBER_MILLISECONDS_IN_DAY; } 

Pendekatan pada kode di atas biasanya terlihat pada kode Java. Angka "ajaib" sekarang didefinisikan sebagai konstanta yang dapat digunakan kembali di lebih dari satu tempat. Meskipun ini bisa dibilang peningkatan, TimeUnitmemungkinkan kami untuk melakukan peningkatan lebih lanjut pada kode ini.

 /** * Convert provided number of milliseconds into number of days. * * @param numberMilliseconds Number of milliseconds to be converted into days. * @return Number of days corresponding to number of provided milliseconds. */ private static long convertMillisecondsToDaysViaTimeUnit(final long numberMilliseconds) { return TimeUnit.MILLISECONDS.toDays(numberMilliseconds); } 

Kode ini mengambil keuntungan dari TimeUnitkonstanta enum MILLISECONDS dan metode toDays (long) untuk dengan mudah melakukan konversi ini adalah cara standar dan sangat mudah dibaca. Tidak ada angka ajaib yang terlihat!

Contoh di atas menunjukkan bagaimana TimeUnitdapat digunakan bahkan ketika konkurensi tidak terlibat. Selain itu MILLISECONDS, representasi unit waktu lain yang disediakan oleh TimeUnittermasuk DAYS, HOURS, MICROSECONDS, MINUTES, NANOSECONDS, dan SECONDS. Ini mencakup satuan waktu yang paling sering digunakan yang akan dibutuhkan seseorang.

Metode pada TimeUnitenum memungkinkan konversi yang mudah dari satuan yang diwakili oleh konstanta enum ke satuan waktu yang berbeda. Ada metode konversi umum TimeUnit.convert (long, TimeUnit) yang dapat digunakan untuk tujuan ini. Metode yang lebih spesifik juga tersedia untuk mengonversi ke jenis unit waktu tertentu sehingga parameter kedua tidak perlu diterapkan. Metode ini termasuk yang telah ditunjukkan toDays(long)serta toHours (long), toMicros (long), toMillis (long), toMinutes (long), toNanos (long), dan toSeconds (long). Meskipun sebagian besar dari enum ini diperkenalkan dengan J2SE 5, metode toMinutes(long), toHours(long)dan toDays(long)diperkenalkan dengan Java SE 6.

Konstanta enum dan metode yang TimeUnitdidefinisikan sejauh ini tidak secara spesifik dikaitkan dengan konkurensi dan umumnya berguna. The TimeUnitenum menawarkan tiga metode tambahan yang menarik. TimeUnit.sleep (long) menyediakan Thread.sleep lebih mudah dibaca (long, int). Konstanta enum dari TimeUnitmenyiratkan satuan waktu yang berlaku, jadi hanya bilangan dasar yang perlu diberikan. Implikasinya di sini, tentu saja, adalah bahwa angka yang lebih jelas dapat diberikan untuk tidur daripada perlu khawatir tentang mengungkapkan angka besar dalam milidetik atau bahkan mengingat bahwa metode tersebut memerlukan waktu yang ditentukan dalam milidetik.

Dua metode berguna terkait lainnya yang tersedia di TimeUnitadalah TimeUnit.timedJoin (Thread, long) [metode praktis untuk Thread.join] dan TimeUnit.timedWait (Thread, long) [metode praktis untuk Object.wait].

Saya telah menggunakan posting ini untuk mendemonstrasikan bagaimana TimeUnityang paling jelas berguna: ini membantu pengembang untuk menulis kode yang jelas tanpa menggunakan angka ajaib untuk mengonversi antara unit pengukuran waktu yang berbeda. Ini berguna dengan sendirinya karena API yang berbeda sering kali mengharapkan unit waktu yang berbeda. Namun, TimeUnitmemiliki manfaat di luar manfaat fungsionalitas yang dimaksudkan dengan jelas. The TimeUnitenum menunjukkan off kekuatan enum Jawa dan bagaimana kekuatan ini dapat dimanfaatkan. Saya melihat ini selanjutnya.

Sebagian besar dari kita yang beralih dari C ++ ke Java ketinggalan memiliki enum dalam versi Java sebelum J2SE 5. Untungnya, penantian itu sepadan karena enum Java jauh lebih unggul daripada enum C ++. Ada banyak cara di mana enum Java lebih baik daripada enum C ++, tetapi salah satu keuntungan utamanya adalah kemampuan untuk mengimplementasikan metode pada enum. Hal ini ditunjukkan pada contoh di atas di mana toDays(long)metode memungkinkan konversi milidetik yang mudah melalui MILLISECONDS.toDays(long)panggilan. Enum Java lebih dari sekadar enkapsulasi sekumpulan nilai integral yang terbatas. Kemampuan untuk menambahkan perilaku ke konstanta enum ini sangat kuat.

Ada dua pendekatan utama untuk menentukan metode pada enum. Salah satu pendekatannya adalah dengan mendefinisikan metode pada tingkat enum keseluruhan dan menggantinya satu per satu pada setiap tingkat konstanta enum. Pendekatan lainnya adalah mengimplementasikan metode sekali untuk seluruh enum dan semua konstanta enumnya tanpa perlu mengganti definisi tunggal. Dengan kata lain, satu pendekatan adalah menulis implementasi metode untuk setiap konstanta enum dan pendekatan lainnya menulis metode yang dibagikan oleh semua konstanta enum. The TimeUnitenum menunjukkan kedua pendekatan. convertMetode umumnya dan semua kenyamanantoXXXXXmetode (XXXXX adalah hal-hal seperti Jam atau Hari) ditulis secara khusus untuk setiap konstanta enum dan metode induk pada tingkat enum keseluruhan akan menampilkan AbstractMethodError jika tidak diganti dengan benar oleh setiap konstanta enum (untungnya selalu demikian!). Metode publik yang tersisa ( timedWait,, timedJoindan sleep) ditulis dengan pendekatan kedua: implementasi metode tunggal ada untuk masing-masing metode yang digunakan oleh konstanta enum yang ditentukan untuk TimeUnit.

Selain kegunaannya dalam menyediakan konversi satuan waktu yang sangat mudah dibaca dan di samping kegunaannya dalam mendemonstrasikan keuntungan signifikan dari enum Java, TimeUnitmemberikan contoh satu prinsip "sering kali benar" di Java: kelas yang sangat dan umumnya berguna (atau enum dalam kasus ini) sering kali dapat ditemukan di SDK tempat yang paling tidak Anda duga. Meskipun kegunaanTimeUnitterlihat jelas dalam aplikasi konkuren, kegunaannya melampaui fungsionalitas konkuren. Ini bukan satu-satunya kasus di mana konstruksi yang lebih berguna secara umum tersedia di JDK dalam paket yang lebih khusus. Saya sering melihat ini dalam proyek yang saya kerjakan juga. Seringkali sebuah tim akan mengumpulkan kelas atau enum yang bagus untuk penggunaan mereka sendiri yang lebih umum diterapkan, tetapi yang berakhir pada paket yang agak khusus daripada berada dalam paket yang lebih dapat diakses secara umum.

Ketika kita membangun rutinitas konversi waktu kita sendiri, kita biasanya melihat angka hard-code (atau konstanta yang didefinisikan sebagai) dengan nilai seperti 1000, 60, dan 24. Jadi, tidak mengherankan bahwa kode sumber untuk TimeUnit mendefinisikan ini sebagai konstanta yang itu digunakan dalam konversinya sendiri. Akhirnya, karet harus mencapai jalan dan konversi ini harus dilakukan dengan angka-angka yang sulit ini. Perbedaannya adalah bahwa penggunaan TimeUnitmemungkinkan kita untuk menetapkan nomor tersebut dan digunakan di luar kode langsung kita dalam enum yang teruji dengan baik dan tersedia secara standar. Menarik juga untuk dicatat bahwa bilangan bulat berkode keras digunakan dalam versi awal TimeUnit, tetapi akhirnya diganti dengan konstanta yang ditentukan secara internal:

// Handy constants for conversion methods static final long C0 = 1L; static final long C1 = C0 * 1000L; static final long C2 = C1 * 1000L; static final long C3 = C2 * 1000L; static final long C4 = C3 * 60L; static final long C5 = C4 * 60L; static final long C6 = C5 * 24L; 

Posting ini sudah panjang, tapi saya ingin memasukkan satu hal lagi. Ini adalah script Groovy sederhana yang digunakan TimeUnituntuk menunjukkan berapa jam, menit, detik, milidetik, mikrodetik, dan nanodetik dalam satu hari.

showTimeUnitConversionFactors.groovy

#!/usr/bin/env groovy // showTimeUnitConversionFactors.groovy import java.util.concurrent.TimeUnit println "IN A SINGLE DAY" println "\tHours: ${TimeUnit.DAYS.toHours(1)}" println "\tMinutes: ${TimeUnit.DAYS.toMinutes(1)}" println "\tSeconds: ${TimeUnit.DAYS.toSeconds(1)}" println "\tMilliseconds: ${TimeUnit.DAYS.toMillis(1)}" println "\tMicroseconds: ${TimeUnit.DAYS.toMicros(1)}" println "\tNanoseconds: ${TimeUnit.DAYS.toNanos(1)}" 

Output dari menjalankan skrip Groovy ini ditampilkan berikut:

Kesimpulan

The TimeUnitenum jelas berguna untuk mengkonversi antara unit waktu dalam pendekatan yang sangat mudah dibaca dan standar. Namun, nilainya melampaui itu, karena enum SDK ini adalah contoh kekuatan enum Java dan mendemonstrasikan berbagai cara untuk memanfaatkan kekuatan itu.

Sumber daya tambahan

Ada beberapa posting blog lain yang sangat berwawasan tentang TimeUnit. Ini termasuk Kegunaan java.util.concurrent.TimeUnit, Java TimeUnit: Lebih dari sekedar satuan waktu, Menemukan perbedaan antara dua tanggal di Jawa, dan Konversi Satuan Waktu di Jawa.

Posting asli tersedia di //marxsoftware.blogspot.com/

Artikel ini, "The Highly Useful Java TimeUnit Enum", awalnya diterbitkan oleh JavaWorld.