Adnotări (@Override, @Deprecated, @FunctionalInterface…) în Java

Adnotările (@Nume) adaugă informații despre cod pentru compilator, unelte sau program: @Override, @Deprecated, @SuppressWarnings, @FunctionalInterface.

Sintaxă
@Override
public String toString() { ... }

@Deprecated(since = "2.0", forRemoval = true)
void metodaVeche() { ... }

@SuppressWarnings("unchecked")
@FunctionalInterface
@interface MyAnnotation { String value(); }   // adnotare proprie

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 din Object ră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 este CLASS, 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.