1. O problema do instanceof clássico
Vamos começar com um pouco de nostalgia. Antes do Java 16, quando você precisava verificar o tipo de um objeto e depois usá-lo como esse tipo, era preciso escrever um padrão prolixo com a verificação instanceof e um casting explícito:
Object obj = ...; // algum objeto
if (obj instanceof String) {
String s = (String) obj;
System.out.println("Tamanho da string: " + s.length());
}
Chato, mas comum
Esse padrão aparece com muita frequência — manipuladores de eventos, trabalho com coleções heterogêneas, regras de negócio com herança etc.
Por que isso é incômodo
- Duplicação de código — você precisa indicar o tipo duas vezes: em instanceof e no casting.
- Risco de erro — é fácil fazer um casting para o tipo errado e receber ClassCastException.
- Código “ruidoso” — piora a legibilidade, especialmente com múltiplas verificações.
2. Pattern Matching para instanceof: nova sintaxe
No Java 16, foi adicionado o pattern matching para instanceof. Agora verificamos o tipo e já declaramos a variável do tipo necessário, disponível dentro do bloco if.
Nova sintaxe
if (obj instanceof String s) {
// s — já é uma String!
System.out.println("Tamanho da string: " + s.length());
}
- Depois do tipo em instanceof escrevemos o nome da nova variável: String s.
- A variável fica disponível apenas dentro do bloco em que a condição é verdadeira.
- Não é preciso escrever o casting (String) — o compilador garante tudo.
Qual é a mágica? O compilador verifica o tipo e, se for compatível, “expõe” a variável do tipo necessário. Caso contrário, o bloco simplesmente não é executado.
Como isso fica em código real
Object obj = "Olá, Java 16+!";
if (obj instanceof String s) {
System.out.println("Maiúsculas: " + s.toUpperCase());
} else {
System.out.println("Não é uma string!");
}
3. Segurança e legibilidade: por que isso é ótimo
Elimina o erro ClassCastException
Object obj = 123;
// String s = (String) obj; // Bum! Exceção.
Com pattern matching, a variável é criada somente quando a verificação de tipo tem sucesso — o “casting errado” simplesmente não existe.
O código fica mais curto e mais claro
Duas linhas viram uma. Menos código “ruidoso” — mais fácil de ler e manter.
Exemplo: tratamento de tipos diferentes
public static void printInfo(Object obj) {
if (obj instanceof String s) {
System.out.println("String com tamanho " + s.length());
} else if (obj instanceof Integer i) {
System.out.println("Número inteiro: " + (i + 1));
} else {
System.out.println("Tipo desconhecido: " + obj);
}
}
4. Exemplos de uso e nuances
Verificação de vários tipos
Object value = ...;
if (value instanceof String s) {
System.out.println("É uma string: " + s);
} else if (value instanceof Number n) {
System.out.println("É um número: " + n);
} else {
System.out.println("Outra coisa: " + value);
}
Uso com null
Se o objeto for null, instanceof sempre retornará false — não haverá NPE, mas o bloco não será executado.
Object obj = null;
if (obj instanceof String s) {
// Este bloco NUNCA será executado se obj == null
System.out.println("String: " + s);
} else {
System.out.println("obj — é null ou não é string");
}
Pattern matching com herança
class Animal {}
class Dog extends Animal {
void bark() { System.out.println("Au!"); }
}
Animal a = new Dog();
if (a instanceof Dog d) {
d.bark(); // Podemos chamar métodos de Dog sem casting!
}
Lembre-se: a ordem das verificações é importante. Vá do mais específico ao mais genérico, caso contrário as verificações “estreitas” podem não ser alcançadas.
Comparação: abordagem antiga e nova
| Forma antiga | Forma nova (pattern matching) |
|---|---|
|
|
5. Restrições do pattern matching para instanceof
- Escopo da variável. A variável do padrão é visível apenas no ramo em que a verificação é verdadeira.
if (obj instanceof String s) {
System.out.println(s); // s está disponível
}
// System.out.println(s); // Erro! s não é visível aqui
- Não é possível declarar várias variáveis de tipos diferentes em uma única condição.
// Erro de compilação:
if (obj instanceof String s || obj instanceof Integer i) {
// ...
}
- Requer Java 16+. Em versões mais antigas do JDK a nova sintaxe não é suportada.
6. Exemplos práticos (com base em um aplicativo simples)
Vamos imaginar um Gerenciador de Tarefas simples com diferentes tipos de tarefas.
Classes
class Task {
String title;
public Task(String title) { this.title = title; }
}
class BugTask extends Task {
int severity;
public BugTask(String title, int severity) {
super(title);
this.severity = severity;
}
}
class FeatureTask extends Task {
String feature;
public FeatureTask(String title, String feature) {
super(title);
this.feature = feature;
}
}
Processamento com pattern matching
public static void processTask(Task t) {
if (t instanceof BugTask bug) {
System.out.println("Bug: " + bug.title + ", criticidade: " + bug.severity);
} else if (t instanceof FeatureTask feature) {
System.out.println("Recurso: " + feature.title + ", módulo: " + feature.feature);
} else if (t instanceof Task task) {
System.out.println("Tarefa comum: " + task.title);
}
}
7. Nuances úteis
Tabela: pattern matching para instanceof — prós e contras
| Prós | Contras/Restrições |
|---|---|
| Menos código, mais legibilidade | Requer Java 16+ |
| Sem risco de ClassCastException | Variável visível apenas dentro do bloco if |
| Segurança de tipos no nível do compilador | Não funciona para vários tipos em uma única condição |
| Prático para lidar com herança | Pode não ser suportado em IDEs e builds antigos |
| Serve para quaisquer classes |
Esquema visual: como funciona o pattern matching para instanceof
+---------------------------+
| Object obj |
+---------------------------+
|
v
if (obj instanceof Type t)
|
Sim Não
(true) (false)
| |
v v
t disponível t não existe
(código) (sem acesso)
8. Erros típicos ao usar pattern matching para instanceof
Erro nº 1: tentar usar a variável fora do bloco if. Você declarou a variável no padrão; saiu do bloco — a variável não existe mais. O compilador reclama, com razão: “Quem é s?”
Erro nº 2: esperar que instanceof funcione com null. Se o objeto for null, a condição instanceof é sempre falsa, a variável não é criada. Trate null separadamente, se necessário.
Erro nº 3: usar a nova sintaxe em uma versão antiga do JDK/IDE. No Java 11 e anteriores, o pattern matching para instanceof não está disponível — você receberá um erro de sintaxe. Verifique a versão do JDK.
Erro nº 4: confusão com escopo. A variável do padrão está disponível somente no ramo em que a verificação é verdadeira. Fora dele — ela não existe.
Erro nº 5: esperar suporte a vários tipos ao mesmo tempo. Não é possível declarar duas variáveis de tipos diferentes em uma única condição: if (obj instanceof String s || obj instanceof Integer i) — isso não é permitido. Para cada tipo, sua própria verificação.
GO TO FULL VERSION