У 2005 році з появою версії Java 5 нам стало відомо про нові сутності під назвою анотації.

Анотації — це особлива форма синтаксичних метаданих, які можна оголосити в коді. Вони використовуються для анализу коду при компіляції або під час виконання програми. Анотацію можна порівняти з міткою, маркером чи вказівкою для компілятора.

Ти, напевно, вже стикався з анотаціями. Наприклад, при перевизначенні методу батьківського класу перед самим методом ми пишемо @Override. Це і є анотація, яка вказує на те, що батьківський метод буде перевизначено в класі-нащадку.

Синтаксис:

@Override
public int hashCode() {
      return super.hashCode();
}

Одразу зазначу, що анотації можна застосовувати не лише до методів, адже вони використовуються у поєднанні з пакетами, класами, методами, полями та параметрами.

Щоб зрозуміти механізм роботи анотацій, для початку познайомимося з поняттям маркерного інтерфейсу. Необхідність позначати певним чином клас для виконання над ним певних дій існувала у Java-розробників ще з часів виникнення мови.

До Java 5 з цією метою використовували інтерфейс, який не схожий навіть сам на себе і не відповідає своєму призначенню. Він був без методів, не містив жодного контракту — просто позначав клас для відокремлення.

Такий інтерфейс називався маркерним. Із назви зрозуміло, що його завдання — маркувати класи для JVM, компілятора або бібліотеки. Деякі маркерні інтерфейси досі існують. Наприклад, Serializable. Цей маркер дає нам змогу позначити клас, повідомляючи про те, що його екземпляри можна серіалізувати.

Ми переконалися, що використання маркерних інтерфейсів досі існує навіть після виникнення анотацій.

Еквівалентне використання анотації та маркерного інтерфейсу:

@MyAnnotation
public class MyClass {}
public class MyClass implements MarkerInterface {}

Незважаючи на те, що завдання в обох підходів те ж саме, є суттєва відмінність у їхній реалізації. Для прикладу розглянемо інтерфейс та інструкцію визначення приналежності класу до певного виду.

У випадку з інтерфейсом ми позначаємо клас: навіть за неправильного використання та появи помилки вона виявиться на етапі компіляції, і програма не запуститься.

З анотаціями не все так просто: помилка виявиться вже в рантаймі, а це означає, що програма почне виконання, але не завершить його.

Зверни увагу: якщо нам потрібно позначити клас для можливості подальшого використання, його екземпляри потрібно передати до конкретного методу:

public class MyInteger implements Sum {}
interface Sum {};

public static void main(String[] args) throws IOException {
        increase(new MyInteger());
}

public static void increase(Sum count) {
        // TODO
}

Найкраще тут підійде маркерний інтерфейс.

Анотації краще використовувати в разі, коли є необхідність у чомусь більшому. Наприклад, у параметрах, які дозволяє передати анотація.

Давай розглянемо стандартні анотації в JDK:

Анотація Опис Приклад
@Override Вказує, що метод перевизначає метод суперкласу або реалізує метод абстрактного класу чи інтерфейсу.
@Override
public int hashCode() {
        return super.hashCode();
}
@Deprecated Позначає код як застарілий.
@Deprecated
public abstract void method();
@SuppressWarnings Вимикає для анотованого елемента попередження компілятора. Зверни увагу: якщо необхідно вимкнути кілька категорій попереджень, їх слід додати до фігурних дужок, наприклад, @SuppressWarnings ({"unchecked", "cast"}).
public class DocumentsFolder {
   private List documents;

   @SuppressWarnings("unchecked")
public void addDocument(String document) {
            documents.add(document);
   }
}

У цьому прикладі ми намагаємося в методі додати до списку, в якого не визначено тип (дженерік). Компілятор попередить нас про це. Хоча це дуже корисно, іноді “ворнінгів” буває забагато, і вони дуже галасливі. В такому разі можна застосовувати цю анотацію до методу із зазначенням параметра-маркера попередження компілятора. Маркерів існує дуже багато, отже не обов'язково пам'ятати все. Зазвичай IDEA сама підкаже, який поставити.

Ось ще приклад використання із декількома параметрами, що передаються:

@SuppressWarnings({"unchecked", "deprecated"})