JavaRush /Курси /JAVA 25 SELF /Гетери й сетери: синтаксис, найкращі практики

Гетери й сетери: синтаксис, найкращі практики

JAVA 25 SELF
Рівень 15 , Лекція 2
Відкрита

1. Що таке гетери й сетери

Якщо уявити об’єкт як сейф, то його приватні поля — це вміст сейфа, а гетери й сетери — ключі до окремих осередків. Гетери дають змогу дізнатися, що лежить усередині, а сетери — акуратно покласти туди щось нове (але лише якщо ви не покладете туди, скажімо, їжачка замість документів).

Гетер

Гетер — це публічний метод (public), який повертає значення приватного поля (private). Зазвичай його назва починається з get + імʼя поля з великої літери.

public class Person {
    private String name; // Приватне поле

    // Гетер для поля name
    public String getName() {
        return name;
    }
}

Сетер

Сетер — це публічний метод (public), який дає змогу змінити значення приватного поля. Його назва починається з set + імʼя поля з великої літери.

public class Person {
    private String name;

    // Сетер для поля name
    public void setName(String name) {
        this.name = name;
    }
}

Для полів типу boolean

Для полів типу boolean у гетерах прийнято використовувати префікс is:

private boolean active;

public boolean isActive() {
    return active;
}

public void setActive(boolean active) {
    this.active = active;
}

2. Синтаксис і домовленості щодо найменування

Java — мова сувора, але не зануда. Є усталені домовленості, що роблять ваш код зрозумілим для інших розробників (і для вас самих за місяць).

  • Гетер: public Type getНазваПоля()
  • Сетер: public void setНазваПоля(Type value)
  • Гетер для boolean: public boolean isНазваПоля()

Назва поля в імені методу пишеться з великої літери: якщо поле age, то методи будуть getAge() і setAge().

Цю домовленість підтримує стиль JavaBeans, завдяки якому IDE, бібліотеки та фреймворки можуть автоматично знаходити ваші гетери й сетери. Наприклад, якщо ви використовуєте Spring або JavaFX, ці методи «магічно» викликатимуться, коли це знадобиться.

3. Приклади коду

Візьмімо навчальний проєкт — простий застосунок «Контакти» (аналог телефонної книжки) — і додаймо туди правильні гетери й сетери.

Приклад: клас Contact з приватними полями та гетерами/сетерами

public class Contact {
    private String name;
    private String phone;
    private int age;
    private boolean favorite;

    // Гетери
    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

    public int getAge() {
        return age;
    }

    public boolean isFavorite() {
        return favorite;
    }

    // Сетери
    public void setName(String name) {
        this.name = name;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public void setAge(int age) {
        // Приклад перевірки: вік не має бути відʼємним
        if (age < 0) {
            System.out.println("Вік не може бути відʼємним!");
            return;
        }
        this.age = age;
    }

    public void setFavorite(boolean favorite) {
        this.favorite = favorite;
    }
}

Використання в застосунку

Contact friend = new Contact();
friend.setName("Іван Іванов");
friend.setPhone("+1-999-123-45-67");
friend.setAge(25);
friend.setFavorite(true);

System.out.println("Імʼя: " + friend.getName());
System.out.println("Телефон: " + friend.getPhone());
System.out.println("Вік: " + friend.getAge());
System.out.println("Обраний: " + (friend.isFavorite() ? "Так" : "Ні"));

Приклад валідації в сетері

Зверніть увагу, що у сетері setAge ми додали просту перевірку: якщо вік відʼємний, ми не змінюємо поле й виводимо попередження. Це простий спосіб захистити об’єкт від некоректних даних.

4. Найкращі практики: як робити правильно

Не для всіх полів потрібні публічні сетери

Іноді поле має бути лише для читання — наприклад, унікальний ідентифікатор, який присвоюється під час створення об’єкта і надалі не змінюється. У такому разі сетер просто не пишуть:

public class Contact {
    private final int id; // final — не можна змінити після ініціалізації

    public Contact(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    // Немає setId!
}

Використовуйте гетери/сетери для контролю доступу та валідації

public void setName(String name) {
    if (name == null || name.trim().isEmpty()) {
        System.out.println("Імʼя не може бути порожнім!");
        return;
    }
    this.name = name;
}

Не розкривайте внутрішні змінювані об’єкти безпосередньо

Якщо у вас є поле — наприклад, список телефонів:

private String[] phones;

Не варто повертати його напряму через гетер:

public String[] getPhones() {
    return phones; // Погано!
}

Такий код дає змогу зовнішньому коду змінювати список як завгодно — порушуючи інкапсуляцію!

Правильніше: повертати копію масиву:

public String[] getPhones() {
    return Arrays.copyOf(phones, phones.length); // Повертаємо копію
}

Або просто клонувати:

public String[] getPhones() {
    return phones.clone(); 
}

Робіть гетери й сетери зрозумілими та простими

  • Не пишіть складну бізнес-логіку в гетерах/сетерах — їхнє завдання просте: контроль доступу та, за потреби, валідація.
  • Якщо поле не повинно змінюватися — не робіть сетер взагалі.
  • Якщо поле не повинно бути доступне ззовні — не робіть гетер.

5. Автоматична генерація гетерів/сетерів в IDE

Писати аксесори вручну — те ще «задоволення», особливо якщо клас має з десяток полів. На щастя, сучасні IDE (наприклад, IntelliJ IDEA, Eclipse, VS Code із плагінами) уміють генерувати їх автоматично.

В IntelliJ IDEA

  1. Відкрийте клас, поставте курсор усередині тіла класу.
  2. Натисніть Alt+Insert (або Code -> Generate...).
  3. Виберіть Getter and Setter.
  4. Позначте потрібні поля й натисніть OK.

Вуаля! Ваші гетери й сетери з’являться наче за помахом чарівної палички.

В Eclipse

  1. Відкрийте клас.
  2. Клацніть правою кнопкою миші — SourceGenerate Getters and Setters...
  3. Виберіть поля й натисніть OK.

У VS Code (з Java Extension Pack)

  1. Відкрийте файл класу.
  2. У палітрі команд (Ctrl+Shift+P) наберіть Generate getters and setters.
  3. Дотримуйтеся підказок.

6. Розвиток вашого застосунку: інкапсуляція в дії

У попередніх лекціях ви будували простий застосунок для зберігання контактів. Тепер ми можемо поліпшити його, зробивши поля приватними й надавши доступ лише через гетери/сетери.

Було (поганий приклад):

public class Contact {
    public String name;
    public String phone;
    public int age;
}

Проблема: будь-який код може зробити так:

Contact c = new Contact();
c.age = -1000; // Тепер у нас вампір у телефонній книзі!

Стало (хороший приклад):

public class Contact {
    private String name;
    private String phone;
    private int age;

    public void setAge(int age) {
        if (age < 0) {
            System.out.println("Вік не може бути відʼємним!");
            return;
        }
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    // Решта гетерів/сетерів...
}

Тепер неможливо випадково (або навмисно) зламати об’єкт ззовні.

7. Гетери/сетери для обчислюваних і незмінних властивостей

Іноді значення не зберігається в полі, а обчислюється на льоту:

public class Rectangle {
    private int width;
    private int height;

    public int getArea() {
        return width * height;
    }
}

Сетер для площі не потрібен — її не можна встановити напряму, лише змінити ширину або висоту.

8. Гетери й сетери: типові помилки

Помилка № 1: Гетер/сетер порушує інкапсуляцію.
Якщо гетер повертає посилання на внутрішній змінюваний об’єкт (наприклад, на список), зовнішній код може його змінити, оминаючи всі перевірки. Це підриває ідею інкапсуляції.

Помилка № 2: Сетер не перевіряє дані.
Якщо сетер просто присвоює значення, не перевіряючи його, можна отримати некоректний стан об’єкта (наприклад, відʼємний вік або порожнє імʼя).

Помилка № 3: Автоматична генерація сетерів для всіх полів.
IDE може згенерувати сетери для всіх полів, але це не завжди правильно! Наприклад, для ідентифікатора (id) сетер не потрібен.

Помилка № 4: Складна логіка в гетерах/сетерах.
Гетери й сетери мають бути простими. Якщо в них з’являється складна бізнес-логіка, варто винести її в окремі методи.

Помилка № 5: Порушення домовленостей щодо найменування.
Якщо назвати гетер fetchName() замість getName(), деякі фреймворки та бібліотеки не зможуть його розпізнати.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ