Überblick über integrierte Java-Anmerkungen

Übersicht über integrierte Java-Anmerkungen

1. Overview

In diesem Artikel werden wir über eine Kernfunktion der Java-Sprache sprechen - die Standardanmerkungen, die im JDK verfügbar sind.

2. Was für eine Anmerkung ist

Einfach ausgedrückt sind AnmerkungenJava types that are preceded by an “@” symbol.

Java hat seit der Version 1.5 Anmerkungen. Seitdem haben sie die Art und Weise geprägt, wie wir unsere Anwendungen entworfen haben.

Spring und Hibernate sind großartige Beispiele für Frameworks, die sich stark auf Anmerkungen stützen, um verschiedene Designtechniken zu ermöglichen.

Grundsätzlichan annotation assigns extra metadata to the source code it’s bound to. Durch Hinzufügen einer Anmerkung zu einer Methode, Schnittstelle, Klasse oder einem Feld können wir:

  1. Informieren Sie den Compiler über Warnungen und Fehler

  2. Manipulieren Sie den Quellcode zur Kompilierungszeit

  3. Ändern oder untersuchen Sie das Verhalten zur Laufzeit

3. Integrierte Java-Anmerkungen

Nachdem wir uns die Grundlagen angesehen haben, werfen wir einen Blick auf einige Anmerkungen, die im Lieferumfang von Java enthalten sind. Erstens gibt es mehrere, die die Zusammenstellung informieren:

  1. @Override

  2. @ SuppressWarnings

  3. @ Veraltet

  4. @SafeVarargs

  5. @FunctionalInterface

Diese Anmerkungen erzeugen oder unterdrücken Compiler-Warnungen und -Fehler. Ihre konsequente Anwendung ist häufig eine gute Methode, da durch das Hinzufügen zukünftiger Programmiererfehler vermieden werden kann.

Die Annotation@Override wird verwendet, um anzugeben, dass eine Methode das Verhalten einer geerbten Methode überschreibt oder ersetzt.

@SuppressWarnings gibt an, dass bestimmte Warnungen aus einem Teil des Codes ignoriert werden sollen. Die Annotation@SafeVarargswirkt sich auch auf eine Art Warnung aus, die sich auf die Verwendung von varargs bezieht.

Die Annotation@Deprecated kann verwendet werden, um eine API als nicht mehr zur Verwendung vorgesehen zu markieren.

Für all diese finden Sie detailliertere Informationen in den verlinkten Artikeln.

3.1. @FunctionalInterface

Mit Java 8 können wir Code auf funktionalere Weise schreiben.

Single Abstract Method interfaces sind ein großer Teil davon. If we intend a SAM interface to be used by lambdas, we can optionally mark it as such with @FunctionalInterface:

@FunctionalInterface
public interface Adder {
    int add(int a, int b);
}

Wie@Override mit Methoden erklärt@FunctionalInterface unsere Absichten mitAdder.

Unabhängig davon, ob wir@FunctionalInterface verwenden oder nicht, können wirAdder immer noch auf dieselbe Weise verwenden:

Adder adder = (a,b) -> a + b;
int result = adder.add(4,5);

Wenn wir jedochAdder, eine zweite Methode hinzufügen, beschwert sich der Compiler:

@FunctionalInterface
public interface Adder {
    // compiler complains that the interface is not a SAM

    int add(int a, int b);
    int div(int a, int b);
}

Dies würde nun ohne die Annotation@FunctionalInterfacekompiliert. Also, was gibt es uns?

Wie@Override schützt uns diese Anmerkung vor zukünftigen Programmiererfehlern. Even though it’s legal to have more than one method on an interface, it isn’t when that interface is being used as a lambda target. Ohne diese Annotation würde der Compiler an Dutzenden von Stellen brechen, an denenAdder als Lambda verwendet wurde. Nunit just breaks in Adder itself.

4. Meta-Annotationen

Als nächstes sind Meta-Annotationen Annotationen, die auf andere Annotationen angewendet werden können.

Diese Meta-Annotationen werden beispielsweise für die Annotationskonfiguration verwendet:

  1. @Ziel

  2. @ Zurückhaltung

  3. @Vererbt

  4. @Dokumentiert

  5. @Wiederholbar

4.1. @Target

Der Umfang der Anmerkungen kann je nach Anforderung variieren. Während eine Annotation nur mit Methoden verwendet wird, kann eine andere Annotation mit Konstruktor- und Felddeklarationen verwendet werden.

Um die Zielelemente einer benutzerdefinierten Annotation zu bestimmen, müssen wir sie mit einer@Target-Annotation kennzeichnen.

@Target kann miteight different element types arbeiten. Wenn wir uns den Quellcode von @SafeVarargs ansehen, können wir sehen, dass er nur an Konstruktoren oder Methoden angehängt werden darf:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {
}

4.2. @Retention

Einige Anmerkungen sind als Hinweise für den Compiler gedacht, während andere zur Laufzeit verwendet werden.

We use the @Retention annotation to say where in our program’s lifecycle our annotation applies.

Dazu müssen wir@Retention mit einer von drei Aufbewahrungsrichtlinien konfigurieren:

  1. RetentionPolicy.SOURCE –ist weder für den Compiler noch für die Laufzeit sichtbar

  2. RetentionPolicy.CLASS - für den Compiler sichtbar

  3. RetentionPolicy.RUNTIME – sind für den Compiler und die Laufzeit sichtbar

@Retention ist standardmäßigRetentionPolicy.SOURCE.

Wenn wir eine Anmerkung haben, auf die zur Laufzeit zugegriffen werden soll:

@Retention(RetentionPolicy.RUNTIME)
@Target(TYPE)
public @interface RetentionAnnotation {
}

Wenn wir dann einer Klasse einige Anmerkungen hinzufügen:

@RetentionAnnotation
@Deprecated
public class AnnotatedClass {
}

Jetzt können wir überAnnotatedClass nachdenken, um zu sehen, wie viele Anmerkungen beibehalten werden:

@Test
public void whenAnnotationRetentionPolicyRuntime_shouldAccess() {
    AnnotatedClass anAnnotatedClass = new AnnotatedClass();
    Annotation[] annotations = anAnnotatedClass.getClass().getAnnotations();
    assertThat(annotations.length, is(1));
}

Der Wert ist 1, weil @RetentionAnnotation hat eine Aufbewahrungsrichtlinie vonRUNTIME,@Deprecated nicht.

4.3. @Inherited

In einigen Situationen benötigen wir möglicherweise eine Unterklasse, damit die Anmerkungen an eine übergeordnete Klasse gebunden sind.

Wir können die Annotation@Inheritedverwenden, um unsere Annotation von einer annotierten Klasse zu ihren Unterklassen zu übertragen.

Wenn wir@Inherited auf unsere benutzerdefinierte Annotation anwenden und sie dann aufBaseClass anwenden:

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation {
}

@InheritedAnnotation
public class BaseClass {
}

public class DerivedClass extends BaseClass {
}

Nach dem Erweitern der BaseClass sollten wir dann sehen, dassDerivedClass zur Laufzeit dieselbe Annotation zu haben scheint:

@Test
public void whenAnnotationInherited_thenShouldExist() {
    DerivedClass derivedClass = new DerivedClass();
    InheritedAnnotation annotation = derivedClass.getClass()
      .getAnnotation(InheritedAnnotation.class);

    assertThat(annotation, instanceOf(InheritedAnnotation.class));
}

Ohne die Annotation@Inherited würde der obige Test fehlschlagen.

4.4. @Documented

Standardmäßig dokumentiert Java die Verwendung einer Anmerkung in Javadocs nicht.

But, we can use the @Documented annotation to change Java’s default behavior.

Wenn wir eine benutzerdefinierte Anmerkung erstellen, die@Documented verwendet:

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelCell {
    int value();
}

Wenden Sie es auf das entsprechende Java-Element an:

public class Employee {
    @ExcelCell(0)
    public String name;
}

Dann zeigt das Javadoc vonEmployeedie Verwendung von Anmerkungen an:

image

4.5. @Repeatable

Manchmal kann es nützlich sein, dieselbe Annotation für ein bestimmtes Java-Element mehrmals anzugeben.

Vor Java 7 mussten wir Annotationen zu einer einzigen Container-Annotation zusammenfassen:

@Schedules({
    @Schedule(time = "15:05"),
    @Schedule(time = "23:00")
})
void scheduledAlarm() {
}

Java 7 brachte jedoch einen saubereren Ansatz. Withthe @Repeatable annotation,we can make an annotation repeatable:

@Repeatable(Schedules.class)
public @interface Schedule {
    String time() default "09:00";
}

Um@Repeatable zu verwenden, benötigen wir auch eine Container-Annotation. In diesem Fall werden wir@Schedules wiederverwenden:

public @interface Schedules {
    Schedule[] value();
}

Dies sieht natürlich sehr nach dem aus, was wir vor Java 7 hatten. Der Wert ist jetzt jedoch, dass der Wrapper@Schedules nicht mehr angegeben wird, wenn@Schedule wiederholt werden muss:

@Schedule
@Schedule(time = "15:05")
@Schedule(time = "23:00")
void scheduledAlarm() {
}

Da für Java die Wrapper-Annotation erforderlich ist, war es für uns einfach, von Annotationslisten vor Java 7 auf wiederholbare Annotationen zu migrieren.

5. Fazit

In diesem Artikel haben wir über in Java integrierte Anmerkungen gesprochen, mit denen jeder Java-Entwickler vertraut sein sollte.

Wie immer finden Sie alle Beispiele des Artikels inover on GitHub.