A repetição é a mãe do aprendizado. Embora já tenhamos falado anteriormente sobre a palavra-chave switch do Java , hoje revisaremos o básico e nos aprofundaremos em algumas novas informações.

Java tem dois tipos de construções switch : a instrução switch e a expressão switch. A expressão switch tornou-se oficial no Java 14, tendo existido em duas variantes "preview" não oficiais nas versões 12 e 13.

Mas vamos começar do começo. Vamos relembrar como era um bom e velho switch antes da versão 12:

public String getProductTypeByName(String product) {
    String productType = "";

    switch (product) {
        case "Apple":
            productType = "Fruit";
            break;

        case "Peach":
            productType = "Fruit";
            break;

        case "Raspberry":
            productType = "Berry";
            break;

        case "Cherry":
            productType = "Berry";
            break;

        case "Tomato":
            productType = "Vegetable";
            break;

        default:
            productType = "other";
            break;
    }

    return productType;
}

Uma instrução switch é um conjunto de construções que serão executadas uma após a outra. Não permite que você retorne um valor. O principal problema com o uso de uma instrução switch é que você pode adicionar um número infinito de expressões case , e essa capacidade costuma ser abusada pelos programadores.

O Java 12 viu a adição de um recurso experimental: uma nova versão de switch — não uma instrução switch, mas uma expressão switch — que pode gerar um valor, usar programação funcional internamente e mesclar instruções case que têm um valor comum, tornando assim o construir compacto.

No Java 12, você pode reescrever o método getProductTypeByName() da seguinte maneira:

public String getProductTypeByName(String product) {
    return switch (product) {
        case "Apple", "Peach" -> "Fruit";
        case "Raspberry", "Cherry" -> "Berry";
        case "Tomato" -> "Vegetable";
        default -> "other";

    };
}

Agora o código parece mais limpo. A sintaxe de seta da programação funcional nos permite retornar valores sem a palavra-chave break e, em geral, o resultado da execução da opção agora pode ser salvo em uma variável ou retornado por meio da palavra-chave return .

Se precisarmos não apenas retornar um resultado, mas também ter várias linhas de código, nossa opção ficaria assim:

public String getProductTypeByName(String product) {
    var result = switch (product) {
        case "Apple", "Peach" -> {
            System.out.println("This is a Fruit");
            break "Fruit";
        }
        case "Raspberry", "Cherry" -> {
            System.out.println("This is a Berry");
            break "Berry";
        }
        case "Tomato" -> {
            System.out.println("This is a Vegetable");
            break "Vegetable";
        }
        default -> {
            break "other";
        }

    };
     return result;
}

No Java 13, a expressão switch ainda era um recurso experimental. Para disponibilizá-lo, assim como no Java 12, você precisa usar o comando --enable-preview ao compilar e executar. A principal e essencialmente única "inovação" do switch no Java 13 é a palavra-chave yield , que substituiu break .

public String getProductTypeByName(String product) {
    var result = switch (product) {
        case "Apple", "Peach" -> {
            System.out.println("This is a Fruit");
            yield "Fruit";
        }
        case "Raspberry", "Cherry" -> {
            System.out.println("This is a Berry");
            yield "Berry";
        }
        case "Tomato" -> {
            System.out.println("This is a Vegetable");
            yield "Vegetables";
        }
        default -> {
            System.out.println("Other");
            yield "other";
        }

    };
    return result;
}

A principal diferença entre yield e break é que break retorna o controle de execução de uma instrução case , mas yield retorna o resultado de switch inteiro , agindo como uma instrução return interna.

No Java 14, o operador instanceof mudou e agora pode ser usado assim:

if (o instanceof String s) {
s.toLowerCase();
}

Em vez da maneira antiga e um tanto feia, onde você tinha que não apenas verificar a variável usando instanceof , mas também convertê-la em um tipo específico.

if(s instanceof String) {
((String) s).toLowerCase();
}

Essas mudanças fazem parte do projeto Amber, que visa adicionar suporte a correspondência de padrões para Java.

Graças à alteração no operador instanceof na versão 14 e uma extensão na versão 16, a correspondência de padrões chegou à versão 17, afinal. É verdade que existe apenas como uma prévia por enquanto. Você pode experimentá-lo com --enable-preview :

public String getObjectType(Object object) {
    return switch (object) {
        case Integer i -> "Integer";
        case Long l -> "Long";
        case String s -> "String";
        default -> object.toString();
    };
}

Em geral, cada nova versão traz mais e mais recursos interessantes para a linguagem, o que torna o desenvolvimento em Java ainda mais legal.