DEV Community

Cover image for Java 15 se tornou GA!
Gabriel Suaki
Gabriel Suaki

Posted on

Java 15 se tornou GA!

Cover image - Java 15

15/09/20 - Java 15 se torna GA.

Além das preview features, conhecidas das versões anteriores (Text Blocks, Pattern Matching para instanceof e Records), foi introduzido no Java 15 os conceitos de sealed classes e Local interfaces & enums.

1. Getting Started

Para começar vamos instalar a JDK 15. Eu utilizo o sdkman para gerenciar todas as JDKs do meu workspace, mas se achar mais conveniente baixar direto da OpenJDK, este é o link.

Utilizando o sdkman, primeiro listamos as JDKs disponíveis:

sdk list java
Enter fullscreen mode Exit fullscreen mode

sdk list java result

Em seguida, basta executar o comando com o identifier encontrado:

sdk install java 15.ea.36-open
Enter fullscreen mode Exit fullscreen mode

Pronto! A JDK está instalada e pronta para ser usada. Agora basta configurar o IntelliJ:

IntelliJ config

2. Sealed Classes & Interfaces (Preview)

Essa funcionalidade permite assumir o controle da hierarquia de classes e interfaces através da keyword sealed e permits. Vamos ao exemplo:

sealed public interface Shape permits Circle, Square, Rectangle, Diamond { }
Enter fullscreen mode Exit fullscreen mode

No código acima, definimos a interface Shape e marcamos como sealed. Classes sealed demandam a declaração da keyword permits para dizer ao compilador quais as classes ou interfaces poderão estender ou implementar Shape. Existe uma exceção a regra somente para casos onde as implementações estão no mesmo arquivo que a sealed class. Quando isto ocorre, podemos omitir a keyword permits da declaração da sealed class.

Classes cuja classe pai é sealed demandam declarar sua abrangência de hierarquia entre: final, non-sealed ou sealed.

Normalmente, as classes filhas serão final para evitar que possam ser herdadas. Ao tentar herdar, observará um erro de compilação.

final class Square implements Shape { }

class TimesSquare extends Square { } // Compilador fica chateado, pois Square é final.
Enter fullscreen mode Exit fullscreen mode

Também é possível substituir o uso da final class por record, pois são classes imutáveis e, por baixo dos panos, o compilador gera um final class.

record Square() implements Shape { }
Enter fullscreen mode Exit fullscreen mode

As estruturas filhas declaradas como non-sealed expandem a hierarquia, possibilitando-as de serem estendidas ou implementadas por qualquer outra classe ou interface.

non-sealed interface Diamond extends Shape { }

non-sealed class Circle implements Shape { }

class BigCircle extends Circle { }

interface ColoredDiamond extends Diamond {}
Enter fullscreen mode Exit fullscreen mode

Deve-se atentar que non-sealed classes podem quebrar a coesão de seus modelos, pois voltam a expor tudo o que tentou proteger com sealed.

Por último, e não menos importante, podemos ter sealed classes implementando sealed classes. Dessa forma, não deixamos tão aberto quanto as non-sealed e nem tão engessado quanto as final, continuamos restringindo a herança ou composição.

sealed class Rectangle implements Shape permits CustomRectangle { }

final class CustomRectangle extends Rectangle { }
Enter fullscreen mode Exit fullscreen mode

2.1. Type-Test Pattern matching

Com o controle de hierarquia que as sealed classes proveem ao compilador, seria possível fazer type-test-pattern igual ao que vemos no when do Kotlin.

public Double getAreaOfShape(final Shape shape) {
    return switch (shape) {
        case Circle c -> circleArea(c);
        case Diamond d -> diamondArea(d);
        case Rectangle r -> rectangleArea(r);
        case Square s -> squareArea(s);
    };
}
Enter fullscreen mode Exit fullscreen mode

Atualmente esse código acima não compila, pois type-test-pattern no switch-case não é uma funcionalidade ainda, é apenas uma possibilidade. A razão disso, é por conta do precedente que foi adicionado ao Java 14: Pattern Matching for instanceof.

Indo mais além, pelo fato do compilador saber exatamente quem implementa determinada sealed class, seria possível omitir o default no switch-case, pois todas as possibilidades foram declaradas.

3. Local interfaces e enums

Com a segunda preview de Records (JEP 384) assomado no Java 15, a possibilidade de criar estruturas no escopo local de um método virou realidade. Além das records, agora podemos declarar classes, enums e interfaces dentro do escopo de métodos também!

  public List<TV> getTop5ExpensiveTV(final List<TV> tvs) {

    enum Price {EXPENSIVE, CHEAP}

    record TVPrice(TV tv, Double amount) { 

      Price price() {
        return amount > 4_000 ? Price.EXPENSIVE : Price.CHEAP;
      }
    }

    return tvs.stream()
        .map(tv -> new TVPrice(tv, calculateAmount(tv)))
        .sorted(Comparator.comparing(TVPrice::price))
        .map(TVPrice::tv)
        .limit(5)
        .collect(Collectors.toList());
  }
Enter fullscreen mode Exit fullscreen mode

O exemplo acima mostra uma forma de usufruir de estruturas locais. Foi utilizado local record e enum para fazer um filtro em uma lista.

5. What’s next?

Existem outras features de melhoria de performance e reimplementações de estruturas, não hesite em ler o release notes completo.

4. Referências

Top comments (0)