W3docs

Método toString() em Java

Sobrescreva toString() em classes Java para gerar representações úteis em string para logging e depuração.

toString é o método que System.out.println, a concatenação de strings e o seu depurador chamam quando precisam renderizar um objeto como texto. O padrão — herdado de Object — é o nome da classe mais um hash hexadecimal ilegível. Sobrescrever toString é uma das coisas mais baratas e de maior retorno que você pode fazer para as pessoas que vão ler seus logs e stack traces (frequentemente uma versão futura de você).

De onde é chamado

Você quase nunca chama toString diretamente. Ele é invocado implicitamente sempre que um objeto é convertido em texto:

Point p = new Point(3, 4);
System.out.println(p);          // calls p.toString()
String msg = "got " + p;        // calls p.toString()
log.info("point: {}", p);       // calls p.toString()

Em qualquer lugar onde um Object aparece em um contexto que espera uma String, toString é executado. É por isso que o padrão é tão decepcionante — ele aparece em todo lugar e não te diz nada útil.

O padrão

Object.toString() retorna getClass().getName() + "@" + Integer.toHexString(hashCode()). Então uma classe simples imprime algo como com.example.Point@1540e19d. A classe está boa; o hex é o hash code de identidade, que é inútil quando você está tentando descobrir o que os campos do objeto contêm.

Uma boa sobrescrita

Um bom toString é curto, inequívoco e contém os dados que um leitor gostaria de ver:

@Override
public String toString() {
  return "Point[x=" + x + ", y=" + y + "]";
}

Algumas convenções que valem a pena seguir:

  • Inclua o nome da classe. Quando uma linha de log mistura objetos, saber que tipo é importa.
  • Use uma forma estável e analisável. Class[field=value, field=value] é o que records e a maioria das bibliotecas Java modernas usam. É legível e fácil de buscar com grep.
  • Mostre os campos que importam — geralmente os que estão em equals. Pule campos enormes (um blob de 10MB, uma Connection).
  • Não inclua segredos. Senhas, tokens, PII — deixe-os de fora, ou mascare-os. toString acaba em arquivos de log.

Com String.format ou blocos de texto

Para mais de três ou quatro campos, String.format (ou um bloco de texto) fica mais legível do que concatenação:

@Override
public String toString() {
  return String.format("User[id=%d, name=%s, role=%s]", id, name, role);
}

Não deixe ser custoso

toString é chamado com mais frequência do que você imagina — frameworks de log renderizam argumentos de forma lazy, mas suficientemente eager para que um toString O(n²) em uma lista de 100k elementos definitivamente deixe o seu serviço lento. Mantenha a saída limitada. O toString de uma coleção deve ser restrito a um head razoável, com ... (N more) para o restante.

Não lance exceções em toString

Lançar uma exceção em toString transforma uma linha de log rotineira em uma NullPointerException em algum lugar inesperado — e o problema subjacente que você estava tentando registrar se perde. Proteja-se contra nulls:

@Override
public String toString() {
  return "Order[id=" + id + ", customer=" + (customer == null ? "<none>" : customer.name()) + "]";
}

Records ganham um de graça

Se sua classe é um portador de dados simples, records já geram um bom toString:

record Point(int x, int y) {}
System.out.println(new Point(3, 4));   // Point[x=3, y=4]

Portanto, sobrescrever toString é algo que você faz principalmente para classes que não são records.

Um exemplo completo

java— editable, runs on the server

O que vem a seguir

toString produz uma descrição de um objeto. O próximo capítulo é sobre como produzir uma cópia de um — clone, Cloneable, e as escolhas de design complicadas em torno de cópias rasas versus profundas. Continue em Clonagem de objetos em Java.

Prática

Prática
Qual destas é a melhor implementação de `toString` para uma classe `Point(int x, int y)`?
Qual destas é a melhor implementação de `toString` para uma classe `Point(int x, int y)`?
Was this page helpful?