O que �?
Saiu recentemente a nova vers�o LTS (Long Term Support) do Java. Essas vers�es s�o as mais importantes no calend�rio de lan�amentos, uma vez que possuem oito anos de suporte.
Desta vez, al�m de melhorias em geral e de performance, um novo recurso chamado sealed classes foi adicionado � linguagem. Ele impactar� nossa forma de usar a heran�a.
Por que � �til?
Heran�a � uma solu��o eficaz para resolver problemas de modelagem. Por�m, como Joshua Bloch apontou em Effective Java, se uma classe deve ser herdada ela precisa ser escrita e bem documentada para tal. Do contr�rio, o c�digo pode n�o funcionar como esperado.
Atualmente em Java a heran�a � controlada de forma bin�ria: uma classe pode ou n�o ser estendida por outras classes. Sealed classes torna esse controle mais granular, permitindo ao autor de uma superclasse descrever quais subclasses devem estend�-la.
Caracter�sticas
- Introduz as palavras-chave sealed e permits para serem usadas com classes ou interfaces
Como utilizar: sintaxe
Para criar uma sealed class ou interface introduzimos a palavra sealed.
Por exemplo, vamos criar a rela��o de heran�a apresentada no diagrama da Figura 1.

O C�digo 1 apresenta a sealed interface Pagavel, descrevendo que apenas PagavelPorDinheiro e PagavelPorCartaoDeCredito devem estend�-la. Tanto classes quanto interfaces podem ser sealed.
public sealed interface Pagavel
permits PagavelPorDinheiro, PagavelPorCartaoDeCredito {}
Agora, ambas as subclasses devem ser declaradas como final, como mostra o C�digo 2.
public final class PagavelPorCartaoDeCredito implements Pagavel {}
public final class PagavelPorDinheiro implements Pagavel {}Dessa forma, temos uma rela��o de heran�a entre as classes documentada pelo c�digo. Somente as classes PagavelPorDinheiro e PagavelPorCartaoDeCredito podem estender a interface Pagavel.
Exemplo pr�tico
Veja agora alguns exemplos pr�ticos de como criar sealed classes.
Exemplo 1 - Nested Classes
No C�digo 3 vemos como declarar uma interface como sealed. Esse c�digo n�o apresenta novidades em rela��o ao anterior, exceto que dessa vez declaramos as classes que implementam a interface, PagavelPorDinheiro e PagavelPorCartaoDeCredito, dentro da pr�pria interface.
public sealed interface Pagavel {
final class PagavelPorDinheiro implements Pagavel {}
final class PagavelPorCartaoDeCredito implements Pagavel {}
}
Essa sintaxe, chamada nested classes, tem sido cada vez mais comum, dada a chegada das sealed classes. Com ela, n�o precisamos colocar as subclasses de Pagavel em arquivos separados.
Exemplo 2 - Classes Abstratas
Classes abstratas tamb�m podem ser sealed. O C�digo 4 mostra como isso pode ser feito.
public abstract sealed class Pagavel
permits PagavelPorCartaoDeCredito, PagavelPorDinheiro {}
Exemplo 3 - Usando permits
No Exemplo 1 mostramos como usar nested classes para declarar, dentro da superclasse, as subclasses que a implementam ou estendem. �s vezes, isso n�o � poss�vel, por exemplo, quando a superclasse e a subclasse est�o em pacotes diferentes.
Em casos assim, declarar todas as classes no mesmo arquivo n�o � poss�vel, uma vez que em Java um pacote corresponde a uma estrutura de pastas em disco. Como alternativa, podemos usar a palavra-chave permits para descrever quais podem ser as subclasses de uma superclasse. O C�digo 5 apresenta como usar permits.
public sealed interface Pagavel
permits PagavelPorDinheiro, PagavelPorCartaoDeCredito {}
Ao usar permits devemos ter cuidado, pois se alguma subclasse for omitida na lista de classes que podem estender ou implementar a superclasse um erro ser� emitido pelo compilador.
Por exemplo, se declararmos uma classe chamada PagavelPorBoleto (C�digo 6), que n�o est� listada na cl�usula permits de Pagavel (C�digo 5), o erro "PagavelPorBoleto is not allowed in the sealed hierarchy" da Figura 2 ser� emitido pelo compilador.
public final class PagavelPorBoleto implements Pagavel {}
Exemplo 4 - instanceof
Continuando o exemplo anterior, considere que agora temos uma classe chamada PagavelPorCartaoDeCredito (C�digo 7), que tamb�m n�o � uma subclasse de Pagavel.
public final class PagavelPorCartaoDeCredito {}Com isso, em tempo de compila��o se pode saber que PagavelPorCartaoDeCredito e Pagavel n�o s�o compat�veis entre si. Conseguir identificar isso em tempo de compila��o modifica o comportamento do operador instanceof, que checa a compatibilidade entre um tipo e um valor.
Por exemplo, no C�digo 8 tentamos checar se PagavelPorCartaoDeCredito � uma inst�ncia de Pagavel. Antes, esse c�digo compilaria e instanceof retornaria false em tempo de execu��o. Agora, ele falhar� em tempo de compila��o, pois o compilador sabe que PagavelPorCartaoDeCredito e Pagavel s�o incompat�veis.
PagavelPorCartaoDeCredito pagavelPorCartaoDeCredito = new PagavelPorCartaoDeCredito();
if(pagavelPorCartaoDeCredito instanceof Pagavel) {
System.out.println("Pag�vel por cart�o de cr�dito");
}
PagavelPorBoleto pagavelPorBoleto = new PagavelPorBoleto();
if(pagavelPorBoleto instanceof Pagavel) {
System.out.println("Pag�vel por boleto");
}Com isso ser� emitido o erro Inconvertible types; cannot cast 'PagavelPorCartaoDeCredito' to 'Pagavel', uma vez que � imposs�vel que PagavelPorCartaoDeCredito seja convertida automaticamente para Pagavel, j� que todas as subclasses de Pagavel s�o conhecidas e PagavelPorCartaoDeCredito n�o � uma delas.
Exemplo 5 - Switch
O switch como express�o, que vemos no C�digo 9, ainda est� em preview, ou seja, embora possamos utiliz�-la n�o h� garantias de que ela sequer existir� em uma vers�o futura.
Com as sealed classes, ao usar switch como express�o, n�o precisamos de uma cl�usula default quando todos os subtipos s�o usados. Isso porque o compilador sabe quais s�o todas as possibilidades que podem ser usadas para uma determinada classe e, caso n�o se use todas elas, o c�digo falhar� em tempo de compila��o.
Pagavel pagavel = new PagavelPorCartaoDeCredito();
switch (pagavel) {
case PagavelPorCartaoDeCredito c -> System.out.println("Pag�vel por cart�o de cr�dito");
case PagavelPorDinheiro d -> System.out.println("Pag�vel por dinheiro");
}Nesse caso, switch funciona como uma alternativa mais concisa a instanceof. Se pagavel for do subtipo PagavelPorCartaoDeCredito o texto "Pag�vel por cart�o de cr�dito" ser� impresso. Caso contr�rio, se Pagavel for do subtipo PagavelPorDinheiro "Pag�vel por dinheiro" ser� impresso.
Conclus�o
Sealed classes, assim como diversas outras funcionalidades do Java, passaram por diversas JEPs (Java Enhacement Proposal). A que corresponde a vers�o final � a JEP 409: Sealed Classes, que pode ser estudada mais a fundo no site do OpenJDK.