Introdução: "Por que simplesmente não tornar os campos public?"
\n\nImagine a situação: você está escrevendo uma classe Person em Java. Ela tem nome, idade e email. A maneira mais simples é declarar os campos como public e acessá-los diretamente:
public class Person {\n public String name;\n public int age;\n public String email;\n}\n\n"Funciona! — você dirá. — Para que preciso desses seus getters e setters? Código extra, linhas se alongam..."
\n\nEsta pergunta é uma das mais populares no Stack Overflow. Milhares de desenvolvedores, especialmente iniciantes, se fazem essa pergunta. A resposta que você receberá de um programador Java experiente será curta: encapsulamento. Mas por trás desta palavra esconde-se toda uma filosofia de design que salva projetos do caos.
\n\nNeste artigo, não vamos apenas dar uma definição. Vamos analisar os problemas reais que getters e setters resolvem (também chamados de accessors e mutators), e mostrar isso com código vivo. Vamos lá!
\n\n1. Encapsulamento: não é apenas uma palavra da moda
\n\nEncapsulamento é um princípio da POO que diz: esconda a estrutura interna do objeto e forneça uma interface controlada para interagir com ele. Getters e setters são exatamente essa interface controlada.
\n\nCompare as duas abordagens:
\n\nAbordagem ruim (campos public)
\nPerson person = new Person();\nperson.age = -5; // Idade negativa? Fácil!\nperson.email = "not-an-email"; // Dados inválidos passam sem verificação\n\nAbordagem boa (getters e setters)
\npublic class Person {\n private String name;\n private int age;\n private String email;\n\n public int getAge() {\n return age;\n }\n\n public void setAge(int age) {\n if (age < 0 || age > 150) {\n throw new IllegalArgumentException("A idade deve estar entre 0 e 150");\n }\n this.age = age;\n }\n\n public String getEmail() {\n return email;\n }\n\n public void setEmail(String email) {\n if (email == null || !email.contains("@")) {\n throw new IllegalArgumentException("Email inválido");\n }\n this.email = email;\n }\n\n // outros getters/setters...\n}\n\nAgora, se alguém tentar definir a idade como -5, o programa lançará uma exceção. Os dados estão protegidos. Aqui está — o poder do encapsulamento.
\n\n2. Validação de dados em tempo real
\n\nSetters são o local ideal para verificar os dados de entrada. Sem eles, você teria que escrever validação em todos os lugares onde atribui um valor. Isso é duplicação de código e o risco de esquecer de verificar em algum lugar.
\n\nExemplo com conta bancária:
\n\npublic class BankAccount {\n private double balance;\n\n public double getBalance() {\n return balance;\n }\n\n public void deposit(double amount) {\n if (amount <= 0) {\n throw new IllegalArgumentException("O valor do depósito deve ser positivo");\n }\n this.balance += amount;\n }\n\n public void withdraw(double amount) {\n if (amount <= 0) {\n throw new IllegalArgumentException("O valor do saque deve ser positivo");\n }\n if (amount > balance) {\n throw new IllegalStateException("Saldo insuficiente");\n }\n this.balance -= amount;\n }\n}\n\nObserve: aqui não há um setter direto para balance. Gerenciamos o saldo através dos métodos deposit e withdraw, que já contêm toda a lógica de verificação. O getter simplesmente retorna o estado atual.
3. Flexibilidade: você pode alterar a implementação sem quebrar o código
\n\nImagine que você armazena a idade em um campo int, e depois decide armazenar a data de nascimento e calcular a idade dinamicamente. Se você tivesse campos públicos, teria que alterar todo o código que acessa
Blogs
Book Recommendations
Leia também
Analisando Unix Timestamp em C#: de timestamp para DateTime e vice-versa
Importação de JSON em TypeScript: guia completo com exemplos
Trabalhando com o sistema de arquivos em Kotlin: guia completo
Quando são necessários destrutores virtuais em C++: análise em 2025
Algoritmos e estruturas de dados em C++: guia prático para desenvolvedores