Programmering

Hvordan beskrive Java-kode med merknader

Du har sannsynligvis møtt situasjoner der du trenger å knytte deg metadata (data som beskriver andre data) med klasser, metoder og / eller andre applikasjonselementer. For eksempel kan programmeringsteamet ditt trenge å identifisere uferdige klasser i et stort program. For hver uferdige klasse vil metadataene sannsynligvis inneholde navnet på utvikleren som er ansvarlig for å fullføre klassen og klassens forventede fullføringsdato.

Før Java 5 var kommentarer den eneste fleksible mekanismen som Java hadde å tilby for å knytte metadata til applikasjonselementer. Kommentarer er imidlertid et dårlig valg. Fordi kompilatoren ignorerer dem, er kommentarer ikke tilgjengelige på kjøretid. Og selv om de var tilgjengelige, måtte teksten analyseres for å få viktige dataelementer. Uten å standardisere hvordan dataelementene er spesifisert, kan disse dataelementene vise seg umulige å analysere.

last ned Få koden Last ned kildekoden for eksempler i denne Java 101-opplæringen. Skapt av Jeff Friesen for.

Ikke-standardiseringsmekanismer

Java gir ikke-standardiserte mekanismer for å knytte metadata til applikasjonselementer. For eksempel flyktig reservert ord lar deg kommentere (knytte data til) felt som skal ekskluderes under serialisering.

Java 5 endret alt ved å introdusere kommentarer, en standardmekanisme for å knytte metadata til forskjellige applikasjonselementer. Denne mekanismen består av fire komponenter:

  • An @grensesnitt mekanisme for å erklære merkingstyper.
  • Meta-annoteringstyper, som du kan bruke til å identifisere applikasjonselementene som en merkingstype gjelder for; for å identifisere levetiden til en kommentar (en forekomst av en merknadstype); og mer.
  • Støtte for behandling av merknader via en utvidelse til Java Reflection API (som skal diskuteres i en fremtidig artikkel), som du kan bruke til å oppdage programets kjøretidskommentarer, og et generelt verktøy for behandling av merknader.
  • Standard merketyper.

Jeg forklarer hvordan du bruker disse komponentene når vi arbeider oss gjennom denne artikkelen.

Erklærer merketyper med @interface

Du kan erklære en merknadstype ved å spesifisere @ symbol umiddelbart etterfulgt av grensesnitt reservert ord og en identifikator. For eksempel erklærer Oppføring 1 en enkel merketype som du kan bruke til å kommentere trådsikker kode.

Oppføring 1:ThreadSafe.java

public @interface ThreadSafe {}

Etter å ha erklært denne merketypen, må du prefiksere metodene du anser som trådsikre med forekomster av denne typen @ umiddelbart etterfulgt av typenavnet til metodens overskrifter. Oppføring 2 gir et enkelt eksempel der hoved() metoden er kommentert @ThreadSafe.

Oppføring 2:AnnDemo.java (versjon 1)

offentlig klasse AnnDemo {@ThreadSafe public static void main (String [] args) {}}

ThreadSafe forekomster gir ingen andre metadata enn navnet på merketypen. Du kan imidlertid levere metadata ved å legge til elementer i denne typen, der en element er en metodehode plassert i kroppen for merknaden.

I tillegg til å ikke ha kodelapper, er elementer underlagt følgende begrensninger:

  • Metodeoverskriften kan ikke erklære parametere.
  • Metodeoverskriften kan ikke gi kaste-klausul.
  • Metodeoverskriftens returtype må være en primitiv type (f.eks. int), java.lang.Streng, java.lang.Klasse, en enum, en merknadstype eller en matrise av en av disse typene. Ingen annen type kan spesifiseres for returtypen.

Som et annet eksempel presenterer Listing 3 a Å gjøre merketype med tre elementer som identifiserer en bestemt kodejobb, spesifiserer datoen når jobben skal avsluttes, og navngir koderen som er ansvarlig for å fullføre jobben.

Oppføring 3:ToDo.java (versjon 1)

offentlig @interface ToDo {int id (); String finishDate (); Strengkoder () er standard "ikke relevant"; }

Merk at hvert element erklærer ingen parameter (er) eller kaste-klausul, har en lovlig returtype (int eller String), og avsluttes med semikolon. Det siste elementet avslører også at en standard returverdi kan spesifiseres; denne verdien returneres når en kommentar ikke tilordner elementet en verdi.

Oppføring 4 bruker Å gjøre å kommentere en uferdig klassemetode.

Oppføring 4:AnnDemo.java (versjon 2)

public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; sorter (byer); } @ToDo (id = 1000, finishDate = "10/10/2019", coder = "John Doe") statisk tomt sortering (Objekt [] objekter) {}}

Oppføring 4 tilordner et metadataelement til hvert element; for eksempel, 1000 er tildelt id. I motsetning til koder, den id og sluttdato elementer må spesifiseres; Ellers rapporterer kompilatoren en feil. Når koder ikke er tildelt en verdi, antar den standardverdien "ikke tilgjengelig" verdi.

Java gir en spesiell Strengverdi() element som kan brukes til å returnere en kommaseparert liste over metadataelementer. Oppføring 5 demonstrerer dette elementet i en ombygd versjon av Å gjøre.

Oppføring 5:ToDo.java (versjon 2)

public @interface ToDo {Strengverdi (); }

Når verdi() er det eneste elementet for en merknadstype, du trenger ikke å spesifisere verdi og = oppdragsoperatør når du tilordner en streng til dette elementet. Oppføring 6 viser begge tilnærminger.

Oppføring 6:AnnDemo.java (versjon 3)

public class AnnDemo {public static void main (String [] args) {String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; sorter (byer); } @ToDo (value = "1000,10 / 10/2019, John Doe") statisk ugyldig sort (Objekt [] objekter) {} @ToDo ("1000,10 / 10/2019, John Doe") statisk boolsk søk ​​( Object [] objects, Object key) {return false; }}

Bruke meta-merknader - problemet med fleksibilitet

Du kan kommentere typer (f.eks. Klasser), metoder, lokale variabler og mer. Denne fleksibiliteten kan imidlertid være problematisk. Det kan for eksempel være lurt å begrense Å gjøre bare til metoder, men ingenting hindrer at den brukes til å kommentere andre applikasjonselementer, som vist i Listing 7.

Oppføring 7:AnnDemo.java (versjon 4)

@ToDo ("1000,10 / 10/2019, John Doe") offentlig klasse AnnDemo {public static void main (String [] args) {@ToDo (value = "1000,10 / 10/2019, John Doe") String [] cities = {"New York", "Melbourne", "Beijing", "Moscow", "Paris", "London"}; sorter (byer); } @ToDo (value = "1000,10 / 10/2019, John Doe") statisk ugyldig sort (Objekt [] objekter) {} @ToDo ("1000,10 / 10/2019, John Doe") statisk boolsk søk ​​( Object [] objects, Object key) {return false; }}

I oppføring 7, Å gjøre brukes også til å kommentere AnnDemo klasse og byer lokal variabel. Tilstedeværelsen av disse feilaktige merknadene kan forvirre noen som vurderer koden din, eller til og med dine egne verktøy for behandling av merknader. For de gangene du trenger å begrense fleksibiliteten til en merketype, tilbyr Java Mål merketype i sin java.lang.annotasjon pakke.

Mål er en meta-merknadstype - en merketype hvis merknader kommenterer merketyper, i motsetning til en ikke-metatilkoblingstype hvis merknader kommenterer applikasjonselementer, for eksempel klasser og metoder. Den identifiserer hvilke applikasjonselementer som en merknadstype gjelder for. Disse elementene er identifisert av Mål’S ElementValue [] verdi () element.

java.lang.annotation.ElementType er et enum der konstanter beskriver applikasjonselementer. For eksempel, BYGGER gjelder for konstruktører og PARAMETER gjelder parametere. Listing 8 refactors Listing 5’s Å gjøre merketype for å begrense den til kun metoder.

Oppføring 8:ToDo.java (versjon 3)

importere java.lang.annotation.ElementType; importere java.lang.annotation.Target; @Target ({ElementType.METHOD}) offentlig @interface ToDo {strengverdi (); }

Gitt refactored Å gjøre merknadstype, et forsøk på å kompilere oppføring 7 resulterer nå i følgende feilmelding:

AnnDemo.java:1: feil: merknadstype gjelder ikke for denne typen erklæring @ToDo ("1000,10 / 10/2019, John Doe") ^ AnnDemo.java:6: feil: merknadstype gjelder ikke for denne typen erklæring @ToDo (verdi = "1000,10 / 10/2019, John Doe") ^ 2 feil

Flere meta-merknader typer

Java 5 introduserte tre ekstra meta-annoteringstyper, som finnes i java.lang.annotasjon pakke:

  • Bevaring angir hvor lange kommentarer med den merkede typen skal beholdes. Denne typen er tilknyttet java.lang.annotation.RetentionPolicy enum erklærer konstanter KLASSE (kompilator registrerer merknader i klassefilen; virtuell maskin beholder dem ikke for å spare minne - standard policy), RUNTIME (kompilator registrerer merknader i klassefilen; virtuell maskin beholder dem), og KILDE (kompilator forkaster merknader).
  • Dokumentert indikerer at forekomster av Dokumentert-kommenterte merknader skal dokumenteres av javadoc og lignende verktøy.
  • Arvet indikerer at en merknadstype arves automatisk.

Java 8 introduserte java.lang.annotation.Repeatable meta-merknadstype. Gjentas brukes til å indikere at merketypen hvis erklæring den (meta-) kommenterer, kan repeteres. Med andre ord, du kan bruke flere kommentarer fra samme repeterbare merknadstype til et applikasjonselement, som vist her:

@ToDo (value = "1000,10 / 10/2019, John Doe") @ToDo (value = "1001,10 / 10/2019, Kate Doe") statisk ugyldig sort (Objekt [] objekter) {}

Dette eksemplet forutsetter det Å gjøre har blitt kommentert med Gjentas merknadstype.

Behandler merknader

Kommentarer er ment å bli behandlet; ellers er det ingen vits i å ha dem. Java 5 utvidet Reflection API for å hjelpe deg med å lage dine egne verktøy for behandling av merknader. For eksempel, Klasse erklærer en Kommentar [] getAnnotations () metode som returnerer en rekke java.lang.Annotasjon tilfeller som beskriver merknader til stede på elementet beskrevet av Klasse gjenstand.

Listing 9 presenterer et enkelt program som laster inn en klassefil, avhører metodene for Å gjøre merknader, og skriver ut komponentene i hver funnet kommentar.

Oppføring 9:AnnProcDemo.java

importere java.lang.reflect.Method; offentlig klasse AnnProcDemo {offentlig statisk ugyldig hoved (String [] args) kaster Unntak {if (args.length! = 1) {System.err.println ("bruk: java AnnProcDemo classfile"); komme tilbake; } Metode [] metoder = Class.forName (args [0]). GetMethods (); for (int i = 0; i <methods.length; i ++) {if (metoder [i] .isAnnotationPresent (ToDo.class)) {ToDo todo = metoder [i] .getAnnotation (ToDo.class); Streng [] komponenter = todo.value (). Split (","); System.out.printf ("ID =% s% n", komponenter [0]); System.out.printf ("Sluttdato =% s% n", komponenter [1]); System.out.printf ("Koder =% s% n% n", komponenter [2]); }}}}

Etter å ha bekreftet at nøyaktig ett kommandolinjeargument (identifisering av en klassefil) er spesifisert, hoved() laster klassefilen via Class.forName (), påkaller getMethods () for å returnere en rekke java.lang.reflect.Methode objekter som identifiserer alle offentlig metoder i klassefilen, og behandler disse metodene.

Metodebehandling begynner med å påkalle Metode’S boolean isAnnotationPresent (Class annotationClass) metode for å avgjøre om merknaden beskrevet av ToDo.klasse er tilstede på metoden. I så fall, Metode’S T getAnnotation (Class annotationClass) metoden kalles for å få merknaden.

De Å gjøre merknader som behandles er de hvis typer erklærer en singel Strengverdi() element (se oppføring 5). Fordi dette elementets strengbaserte metadata er kommaseparert, må det deles inn i en rekke komponentverdier. Hver av de tre komponentverdiene blir deretter åpnet og sendt ut.

Kompiler denne kildekoden (javac AnnProcDemo.java). Før du kan kjøre applikasjonen, trenger du en passende klassefil med @Å gjøre merknader om det offentlig metoder. For eksempel kan du endre Listing 6’s AnnDemo kildekode som skal inkluderes offentlig i sin sortere() og Søk() metodeoverskrifter. Du trenger også oppføring 10-tallet Å gjøre merketype, som krever RUNTIME oppbevaringspolitikk.

Oppføring 10:ToDo.java (versjon 4)

importere java.lang.annotation.ElementType; importere java.lang.annotation.Retention; importere java.lang.annotation.RetentionPolicy; importere java.lang.annotation.Target; @Target ({ElementType.METHOD}) @Retention (RetentionPolicy.RUNTIME) public @interface ToDo {Strengverdi (); }

Kompiler den modifiserte AnnDemo.java og Listing 10, og utfør følgende kommando for å behandle AnnDemo’S Å gjøre kommentarer:

java AnnProcDemo AnnDemo

Hvis alt går bra, bør du følge følgende utdata:

ID = 1000 sluttdato = 10.10.2019 Koder = John Doe ID = 1000 sluttdato = 10.10.2019 Koder = John Doe

Behandler merknader med apt og Java-kompilatoren

Java 5 introduserte en apt verktøy for å behandle merknader på en generalisert måte. Java 6 migrerte aptFunksjonalitet i sin javac kompilatorverktøy, og Java 7 avviklet apt, som deretter ble fjernet (startende med Java 8).

Standard merketyper

Sammen med Mål, Bevaring, Dokumentert, og Arvet, Introduserte Java 5 java.lang. utdatert, java.lang.Override, og java.lang.SuppressWarnings. Disse tre merketypene er designet for kun å brukes i en kompilatorkontekst, og det er derfor deres retensjonspolitikk er satt til KILDE.

Foreldet