Ce face Adnotări (@Override, @Deprecated, @FunctionalInterface...)
O adnotare începe cu @ și se pune înaintea unei declarații (clasă, metodă, câmp, parametru). Nu schimbă direct ce face codul, ci îl descrie. Cele mai folosite sunt verificate de compilator: @Override (eroare dacă metoda nu rescrie de fapt nimic), @FunctionalInterface (eroare dacă interfața nu are exact o metodă abstractă) și @Deprecated (avertisment pentru cine folosește elementul).
@SuppressWarnings("...") oprește un anumit avertisment pentru o declarație, de exemplu "unchecked" sau "deprecation". Folosește-l cât mai local și numai după ce ai înțeles de ce apare avertismentul. @SafeVarargs marchează metodele generice cu parametri variabili ca fiind sigure.
Poți declara adnotări proprii cu @interface. Cu @Retention(RetentionPolicy.RUNTIME), adnotarea rămâne disponibilă la rulare și poate fi citită prin reflecție; așa funcționează framework-uri ca JUnit (@Test) sau Spring (@Autowired).
Exemple
Exemplul 1: @Override și @FunctionalInterface
@Override confirmă că toString și calculeaza rescriu metode existente. @FunctionalInterface garantează că Reducere poate primi o lambda.
@FunctionalInterface
interface Reducere {
double calculeaza(double pret);
}
class ReducereStudent implements Reducere {
@Override
public double calculeaza(double pret) {
return pret * 0.5;
}
@Override
public String toString() {
return "reducere student 50%";
}
}
public class Main {
public static void main(String[] args) {
Reducere student = new ReducereStudent();
Reducere blackFriday = pret -> pret * 0.7;
System.out.println(student + ": " + student.calculeaza(80) + " lei");
System.out.println("Black Friday: " + blackFriday.calculeaza(80) + " lei");
}
}
Rezultat
reducere student 50%: 40.0 lei
Black Friday: 56.0 lei
Exemplul 2: @Deprecated cu since și forRemoval
Metoda veche este marcată ca depreciată. Atributele adnotării se pot citi și la rulare, prin reflecție. Apelul din aceeași clasă nu produce avertisment; dintr-o altă clasă, javac ar semnala [removal].
import java.lang.reflect.Method;
public class Main {
/** Folosește {@link #pretFinal(double, double)}. */
@Deprecated(since = "2.0", forRemoval = true)
static double pretCuTva(double pret) {
return pret * 1.19;
}
static double pretFinal(double pret, double cotaTva) {
return pret * (1 + cotaTva);
}
public static void main(String[] args) throws Exception {
System.out.println("vechi: " + pretCuTva(100));
System.out.println("nou: " + pretFinal(100, 0.21));
Method m = Main.class.getDeclaredMethod("pretCuTva", double.class);
Deprecated d = m.getAnnotation(Deprecated.class);
System.out.println("depreciată din versiunea " + d.since() + ", va fi ștearsă: " + d.forRemoval());
}
}
Rezultat
vechi: 119.0
nou: 121.0
depreciată din versiunea 2.0, va fi ștearsă: true
Exemplul 3: O adnotare proprie citită la rulare
@Verificare este păstrată la rulare (RUNTIME). Programul caută metodele marcate, le apelează și compară rezultatul cu valoarea așteptată, ca un mini-framework de teste. Al doilea test eșuează intenționat: „Cluj-Napoca” are 11 caractere, nu 5. Metoda ajutator nu are adnotarea, deci este sărită.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Verificare {
String asteptat();
}
class Teste {
@Verificare(asteptat = "IAȘI")
static String majuscule() { return "Iași".toUpperCase(); }
@Verificare(asteptat = "5")
static String lungime() { return String.valueOf("Cluj-Napoca".length()); }
static String ajutator() { return "nu e test"; }
}
public class Main {
public static void main(String[] args) throws Exception {
Method[] metode = Teste.class.getDeclaredMethods();
Arrays.sort(metode, Comparator.comparing(Method::getName));
for (Method m : metode) {
Verificare v = m.getAnnotation(Verificare.class);
if (v == null) {
continue;
}
String rezultat = (String) m.invoke(null);
String stare = rezultat.equals(v.asteptat()) ? "OK" : "EȘUAT (a dat " + rezultat + ")";
System.out.println(m.getName() + ": " + stare);
}
}
}
Rezultat
lungime: EȘUAT (a dat 11)
majuscule: OK
Greșeli frecvente
- Nu pui
@Override: o greșeală de scriere (tostring()) creează în tăcere o metodă nouă, iar cea dinObjectrămâne nerescrisă. - Ascunzi avertismente cu
@SuppressWarnings("all")pe toată clasa. Ascunzi și problemele reale; suprimă doar avertismentul exact, pe declarația cea mai mică. - Creezi o adnotare proprie fără
@Retention(RetentionPolicy.RUNTIME)și nu o găsești prin reflecție: implicit esteCLASS, adică nu e vizibilă la rulare.
Comenzi înrudite
Interfețe (interface, implements): O interfață (interface) descrie ce metode trebuie să aibă o clasă; clasa o promite cu implements și poate implementa mai multe interfețe.Moștenire (extends): Cu extends o clasă moștenește câmpurile și metodele altei clase și le poate extinde sau rescrie; Java permite o singură superclasă.Expresii lambda: O lambda este o funcție scurtă, fără nume, scrisă ca parametri -> corp, folosită oriunde se așteaptă o interfață funcțională.javadoc: javadoc generează documentație HTML din comentariile /** … */ scrise înaintea claselor, metodelor și câmpurilor.