Bagaimana mendeskripsikan kode Java dengan penjelasan

Anda mungkin pernah mengalami situasi di mana Anda perlu mengaitkan metadata (data yang mendeskripsikan data lain) dengan kelas, metode, dan / atau elemen aplikasi lainnya. Misalnya, tim pemrograman Anda mungkin perlu mengidentifikasi kelas yang belum selesai dalam aplikasi yang besar. Untuk setiap kelas yang belum selesai, metadata kemungkinan akan menyertakan nama pengembang yang bertanggung jawab untuk menyelesaikan kelas dan tanggal penyelesaian kelas yang diharapkan.

Sebelum Java 5, komentar adalah satu-satunya mekanisme fleksibel yang ditawarkan Java untuk mengaitkan metadata dengan elemen aplikasi. Namun, komentar adalah pilihan yang buruk. Karena kompilator mengabaikannya, komentar tidak tersedia pada waktu proses. Dan bahkan jika tersedia, teks harus diurai untuk mendapatkan item data penting. Tanpa standarisasi bagaimana item data ditentukan, item data ini mungkin terbukti tidak mungkin untuk diurai.

unduh Dapatkan kodenya Unduh kode sumber untuk contoh dalam tutorial Java 101 ini. Dibuat oleh Jeff Friesen untuk.

Mekanisme anotasi nonstandar

Java menyediakan mekanisme nonstandar untuk mengaitkan metadata dengan elemen aplikasi. Misalnya, transientkata khusus memungkinkan Anda menganotasi (mengaitkan data dengan) bidang yang akan dikecualikan selama serialisasi.

Java 5 mengubah segalanya dengan memperkenalkan anotasi , mekanisme standar untuk menghubungkan metadata dengan berbagai elemen aplikasi. Mekanisme ini terdiri dari empat komponen:

  • Sebuah @interfacemekanisme untuk menyatakan jenis anotasi.
  • Jenis anotasi meta, yang dapat Anda gunakan untuk mengidentifikasi elemen aplikasi yang menerapkan jenis anotasi; untuk mengidentifikasi umur anotasi (contoh dari jenis anotasi); dan lainnya.
  • Dukungan untuk pemrosesan anotasi melalui ekstensi ke Java Reflection API (akan dibahas di artikel mendatang), yang dapat Anda gunakan untuk menemukan anotasi waktu proses program, dan alat umum untuk memproses anotasi.
  • Jenis anotasi standar.

Saya akan menjelaskan cara menggunakan komponen ini saat kami mengerjakan artikel ini.

Mendeklarasikan jenis anotasi dengan @interface

Anda dapat mendeklarasikan jenis anotasi dengan menentukan @simbolnya segera diikuti oleh interfacekata yang dipesan dan pengenal. Misalnya, Listing 1 mendeklarasikan jenis anotasi sederhana yang mungkin Anda gunakan untuk membuat anotasi kode aman-thread.

Daftar 1:ThreadSafe.java

public @interface ThreadSafe {}

Setelah mendeklarasikan jenis anotasi ini, berikan awalan pada metode yang Anda anggap aman untuk thread dengan instance jenis ini dengan @segera diikuti dengan nama jenis ke header metode. Kode 2 menawarkan contoh sederhana di mana main()metode dianotasi @ThreadSafe.

Daftar 2:AnnDemo.java (versi 1)

kelas publik AnnDemo {@ThreadSafe public static void main (String [] args) {}}

ThreadSafeInstance tidak menyediakan metadata selain nama jenis anotasi. Namun, Anda dapat menyediakan metadata dengan menambahkan elemen ke jenis ini, di mana elemen adalah header metode yang ditempatkan di badan jenis anotasi.

Selain tidak memiliki badan kode, elemen tunduk pada batasan berikut:

  • Header metode tidak dapat mendeklarasikan parameter.
  • Header metode tidak dapat memberikan klausa lemparan.
  • Metode header tipe kembali harus menjadi tipe primitif (misalnya, int), java.lang.String, java.lang.Class, enum, tipe anotasi, atau sebuah array dari salah satu jenis. Tidak ada tipe lain yang dapat ditentukan untuk tipe pengembalian.

Sebagai contoh lain, Kode 3 menyajikan ToDojenis anotasi dengan tiga elemen yang mengidentifikasi pekerjaan pengkodean tertentu, menentukan tanggal kapan pekerjaan akan selesai, dan penamaan pembuat kode yang bertanggung jawab untuk menyelesaikan pekerjaan.

Kode 3:ToDo.java (versi 1)

Public @interface ToDo {int id (); String finishDate (); Pembuat kode string () default "n / a"; }

Perhatikan bahwa setiap elemen mendeklarasikan tidak ada parameter atau klausa lemparan, memiliki tipe pengembalian resmi ( intatau String), dan diakhiri dengan titik koma. Juga, elemen terakhir mengungkapkan bahwa nilai pengembalian default dapat ditentukan; nilai ini dikembalikan ketika anotasi tidak memberikan nilai ke elemen.

Kode 4 digunakan ToDountuk membubuhi keterangan metode kelas yang belum selesai.

Daftar 4:AnnDemo.java (versi 2)

public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; urutkan (kota); } @ToDo (id = 1000, finishDate = "10/10/2019", coder = "John Doe") sortir kosong statis (Object [] objek) {}}

Kode 4 menetapkan item metadata untuk setiap elemen; misalnya, 1000ditugaskan ke id. Tidak seperti coder, elemen iddan finishDateharus ditentukan; jika tidak, kompilator akan melaporkan kesalahan. Ketika codertidak diberi nilai, itu mengasumsikan "n/a"nilai defaultnya .

Java menyediakan String value()elemen khusus yang dapat digunakan untuk mengembalikan daftar item metadata yang dipisahkan koma. Kode 5 mendemonstrasikan elemen ini dalam versi refactored ToDo.

Kode 5:ToDo.java (versi 2)

public @interface ToDo {String value (); }

When value()adalah satu-satunya elemen jenis anotasi, Anda tidak perlu menentukan valuedan =operator penugasan saat menetapkan string ke elemen ini. Daftar 6 menunjukkan kedua pendekatan tersebut.

Kode 6:AnnDemo.java (versi 3)

public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; urutkan (kota); } @ToDo (value = "1000,10 / 10/2019, John Doe") static void sort (Object [] objek) {} @ToDo ("1000,10 / 10/2019, John Doe") penelusuran boolean statis ( Objek [] objek, kunci Objek) {return false; }}

Menggunakan jenis meta-annotation - masalah fleksibilitas

Anda dapat membuat anotasi tipe (mis., Kelas), metode, variabel lokal, dan banyak lagi. Namun, fleksibilitas ini bisa menimbulkan masalah. Misalnya, Anda mungkin ingin membatasi ToDoke metode saja, tetapi tidak ada yang mencegahnya digunakan untuk membuat anotasi elemen aplikasi lain, seperti yang ditunjukkan dalam Listing 7.

Kode 7:AnnDemo.java (versi 4)

@ToDo ("1000,10 / 10/2019, John Doe") public class AnnDemo {public static void main (String [] args) {@ToDo (value = "1000,10 / 10/2019, John Doe") String [] kota = {"New York", "Melbourne", "Beijing", "Moskow", "Paris", "London"}; urutkan (kota); } @ToDo (value = "1000,10 / 10/2019, John Doe") static void sort (Object [] objek) {} @ToDo ("1000,10 / 10/2019, John Doe") penelusuran boolean statis ( Objek [] objek, kunci Objek) {return false; }}

Dalam Kode 7, ToDojuga digunakan untuk membuat anotasi AnnDemokelas dan citiesvariabel lokal. Kehadiran anotasi yang salah ini mungkin membingungkan seseorang yang sedang meninjau kode Anda, atau bahkan alat pemrosesan anotasi Anda sendiri. Saat Anda perlu mempersempit fleksibilitas jenis anotasi, Java menawarkan Targetjenis anotasi dalam java.lang.annotationpaketnya.

Targetadalah jenis anotasi meta - jenis  anotasi yang anotasinya menganotasi jenis anotasi, berbeda dengan jenis anotasi non-meta yang anotasinya menganotasi elemen aplikasi, seperti kelas dan metode. Ini mengidentifikasi jenis elemen aplikasi yang dapat diterapkan jenis anotasi. Unsur-unsur ini diidentifikasi oleh Target's ElementValue[] value()elemen.

java.lang.annotation.ElementType is an enum whose constants describe application elements. For example, CONSTRUCTOR applies to constructors and PARAMETER applies to parameters. Listing 8 refactors Listing 5’s ToDo annotation type to restrict it to methods only.

Listing 8:ToDo.java (version 3)

import java.lang.annotation.ElementType; import java.lang.annotation.Target; @Target({ElementType.METHOD}) public @interface ToDo { String value(); }

Given the refactored ToDo annotation type, an attempt to compile Listing 7 now results in the following error message:

AnnDemo.java:1: error: annotation type not applicable to this kind of declaration @ToDo("1000,10/10/2019,John Doe") ^ AnnDemo.java:6: error: annotation type not applicable to this kind of declaration @ToDo(value="1000,10/10/2019,John Doe") ^ 2 errors

Additional meta-annotation types

Java 5 introduced three additional meta-annotation types, which are found in the java.lang.annotation package:

  • Retention indicates how long annotations with the annotated type are to be retained. This type’s associated java.lang.annotation.RetentionPolicy enum declares constants CLASS (compiler records annotations in class file; virtual machine doesn’t retain them to save memory — default policy), RUNTIME (compiler records annotations in class file; virtual machine retains them), and SOURCE (compiler discards annotations).
  • Documented indicates that instances of Documented-annotated annotations are to be documented by javadoc and similar tools.
  • Inherited indicates that an annotation type is automatically inherited.

Java 8 introduced the java.lang.annotation.Repeatable meta-annotation type. Repeatable is used to indicate that the annotation type whose declaration it (meta-)annotates is repeatable. In other words, you can apply multiple annotations from the same repeatable annotation type to an application element, as demonstrated here:

@ToDo(value = "1000,10/10/2019,John Doe") @ToDo(value = "1001,10/10/2019,Kate Doe") static void sort(Object[] objects) { }

This example assumes that ToDo has been annotated with the Repeatable annotation type.

Processing annotations

Annotations are meant to be processed; otherwise, there’s no point in having them. Java 5 extended the Reflection API to help you create your own annotation processing tools. For example, Class declares an Annotation[] getAnnotations() method that returns an array of java.lang.Annotation instances describing annotations present on the element described by the Class object.

Listing 9 presents a simple application that loads a class file, interrogates its methods for ToDo annotations, and outputs the components of each found annotation.

Listing 9:AnnProcDemo.java

import java.lang.reflect.Method; public class AnnProcDemo { public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("usage: java AnnProcDemo classfile"); return; } Method[] methods = Class.forName(args[0]).getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].isAnnotationPresent(ToDo.class)) { ToDo todo = methods[i].getAnnotation(ToDo.class); String[] components = todo.value().split(","); System.out.printf("ID = %s%n", components[0]); System.out.printf("Finish date = %s%n", components[1]); System.out.printf("Coder = %s%n%n", components[2]); } } } }

After verifying that exactly one command-line argument (identifying a class file) has been specified, main() loads the class file via Class.forName(), invokes getMethods() to return an array of java.lang.reflect.Method objects identifying all public methods in the class file, and processes these methods.

Method processing begins by invoking Method’s boolean isAnnotationPresent(Class annotationClass) method to determine if the annotation described by ToDo.class is present on the method. If so, Method’s T getAnnotation(Class annotationClass) method is called to obtain the annotation.

The ToDo annotations that are processed are those whose types declare a single String value() element (see Listing 5). Because this element’s string-based metadata is comma-separated, it needs to be split into an array of component values. Each of the three component values is then accessed and output.

Compile this source code (javac AnnProcDemo.java). Before you can run the application, you’ll need a suitable class file with @ToDo annotations on its public methods. For example, you could modify Listing 6’s AnnDemo source code to include public in its sort() and search() method headers. You’ll also need Listing 10’s ToDo annotation type, which requires the RUNTIME retention policy.

Listing 10:ToDo.java (version 4)

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface ToDo { String value(); }

Compile the modified AnnDemo.java and Listing 10, and execute the following command to process AnnDemo’s ToDo annotations:

java AnnProcDemo AnnDemo

If all goes well, you should observe the following output:

ID = 1000 Finish date = 10/10/2019 Coder = John Doe ID = 1000 Finish date = 10/10/2019 Coder = John Doe

Processing annotations with apt and the Java compiler

Java 5 memperkenalkan aptalat untuk memproses anotasi secara umum. Java 6 memigrasikan aptfungsionalitasnya ke dalam javacalat kompilernya, dan Java 7 tidak digunakan lagi apt, yang kemudian dihapus (dimulai dengan Java 8).

Jenis anotasi standar

Seiring dengan Target, Retention, Documented, dan Inherited, Java 5 memperkenalkan java.lang.Deprecated, java.lang.Overridedan java.lang.SuppressWarnings. Ketiga jenis anotasi ini dirancang untuk digunakan dalam konteks compiler saja, itulah alasan kebijakan retensinya disetel ke SOURCE.

Tidak digunakan lagi