W3docs

Getters e Setters em Java

Exponha campos privados com segurança em Java usando métodos getter e setter e adicione validação nos setters.

Um getter é um método que retorna o valor de um campo; um setter é um método que escreve nele. Juntos, são a forma padrão de fornecer acesso controlado a um campo privado. O capítulo anterior sobre encapsulamento explicou o porquê — este capítulo trata do como, incluindo as convenções de nomenclatura, os padrões de validação e quando ignorá-los completamente.

O padrão básico

Um campo, um getter e um setter:

public class User {
  private String email;

  public String getEmail()              { return email; }
  public void   setEmail(String email)  { this.email = email; }
}

Por convenção:

  • O getter é nomeado get<FieldName> para tudo, exceto booleanos.
  • Para um campo boolean, o getter é nomeado is<FieldName> (isActive, hasPermission).
  • O setter é nomeado set<FieldName> e recebe um parâmetro do tipo do campo.
  • Ambos são public, a menos que haja razão para ser diferente.

Essas regras também constituem a convenção JavaBeans — muitas ferramentas (bibliotecas de serialização, mecanismos de template, refatorações de IDE) dependem delas e simplesmente não conseguirão enxergar campos cujos acessores tenham nomes diferentes.

Validação em setters

Um setter é sua única oportunidade de rejeitar uma entrada inválida antes que o campo seja escrito:

public class User {
  private String email;

  public void setEmail(String email) {
    if (email == null || !email.contains("@")) {
      throw new IllegalArgumentException("not a valid email: " + email);
    }
    this.email = email;
  }
}

Um setter sem lógica que apenas atribui não é muito melhor do que um campo público. O ponto de colocar um setter entre os chamadores e o campo é poder inserir uma verificação lá. Se você se pegar escrevendo dezenas de setters que leem como this.x = x;, pergunte-se se a classe realmente precisa ser mutável — um objeto com atributos definidos no construtor e apenas getters (uma classe imutável ou um record) geralmente é uma escolha melhor.

Getters computados e derivados

Um getter não precisa mapear um campo diretamente. Ele pode calcular seu valor de retorno:

public class Rectangle {
  private final double width, height;
  public Rectangle(double w, double h) { this.width = w; this.height = h; }

  public double getWidth()  { return width; }
  public double getHeight() { return height; }
  public double getArea()   { return width * height; }   // derived
}

Para quem chama, getArea() parece exatamente com getWidth() — ambos são apenas métodos que retornam um double. O fato de um ler um valor armazenado e o outro calculá-lo é um detalhe de implementação que você pode alterar sem que ninguém perceba.

Getters somente leitura

Um getter sem setter expõe um campo para leitura, mas o bloqueia para escrita:

public class Order {
  private final long id;
  private final long createdAt;

  public Order(long id, long createdAt) {
    this.id        = id;
    this.createdAt = createdAt;
  }

  public long getId()        { return id; }
  public long getCreatedAt() { return createdAt; }
}

O código externo pode perguntar "qual é o ID?" mas não pode alterá-lo. É assim que campos imutáveis após a construção funcionam na prática.

Nomenclatura booleana: is, has, should

Getters booleanos ficam mais naturais com um prefixo is/has/can/should:

public boolean isActive()        { return active; }
public boolean hasPermission()   { return permission != null; }
public boolean canRetry()        { return retries < maxRetries; }

Combinado com o nome do campo, o local de chamada se lê como uma frase em inglês: if (user.isActive()) { ... }. O setter para esses campos é apenas setActive(boolean), sem o is.

Um detalhe importante: ferramentas JavaBeans derivam o nome da propriedade a partir do acessor, então isActive() e getActive() mapeiam ambos para a propriedade active — mas as ferramentas geralmente procuram acessores com prefixo is somente no tipo primitivo boolean. Para um campo Boolean encapsulado, prefira getActive() para garantir descoberta.

Cópias defensivas (novamente)

Se um getter retornar um objeto interno mutável, retorne uma cópia ou uma visão não modificável:

private final List<String> tags = new ArrayList<>();

public List<String> getTags() {
  return List.copyOf(tags);
}

O mesmo na entrada para um setter:

public void setTags(List<String> tags) {
  this.tags.clear();
  this.tags.addAll(tags);    // copy in
}

Sem essas cópias, o chamador poderia mutar a lista interna tags e contornar tudo o que a classe faz.

Java moderno: acessores mais curtos

Código Java mais recente (especialmente em bibliotecas não vinculadas às ferramentas JavaBeans) frequentemente omite o prefixo get por simetria com a forma como os acessores de record são nomeados:

public class Point {
  private final int x, y;
  public Point(int x, int y) { this.x = x; this.y = y; }
  public int x() { return x; }
  public int y() { return y; }
}

Se você não estiver vinculado ao JavaBeans (sem Hibernate, sem configurações padrão do Jackson, sem JSP), esse estilo é aceitável — e corresponde ao que record Point(int x, int y) {} geraria automaticamente. Escolha um estilo por base de código e aplique-o de forma consistente. Para uma visão completa da abordagem baseada em record, veja records modernos.

Não os gere por reflexo

IDEs modernas geram com prazer um getter e um setter para cada campo com um único atalho de teclado. Resista ao impulso. Cada par gerado é uma decisão de design que você está tomando:

  • Um getter expõe um campo — você realmente quer que os chamadores o leiam?
  • Um setter expõe um caminho de escrita — você realmente quer que os chamadores o alterem?
  • Se ambas as respostas forem incondicionalmente sim, por que o campo é privado?

A resposta certa muitas vezes é "nenhum dos dois" — substitua setBalance(int) por deposit(int) e withdraw(int), que expressam as operações reais.

Um exemplo completo

java— editable, runs on the server

O que vem a seguir

Isso encerra o básico de uma única classe — como declará-la, como controlar seus membros, como expor apenas o suficiente ao mundo externo. O próximo capítulo inicia a segunda grande ideia de POO: herança, onde uma classe se baseia em outra em vez de começar do zero. Continue para herança em Java.

Prática

Prática
Por que um setter geralmente é preferível a tornar o campo público, mesmo que o setter não faça nada além de atribuir?
Por que um setter geralmente é preferível a tornar o campo público, mesmo que o setter não faça nada além de atribuir?
Was this page helpful?