E aee jovens, tudo bem com vocês?
Neste artigo eu irei abordar algumas das novidades que foram aparecendo desde a versão 8 do Java até a 15. Não irei adicionar todas as atualizações pois o artigo ficaria muito grande. No me ponto de vista foram as que chamaram mais atenção, mas temos outras novidades bem interessantes também.
Então bora começar.
Programação Funcional (Java 8)
No Java 8, programação funcional e lambdas foram adicionados como recursos da linguagem. O paradigma principal da programação funcional são valores imutáveis. Os dados passam por um pipeline de etapas de modificação, onde cada etapa pega alguma entrada e mapeia para uma nova saída. A programação funcional pode ser usada com Streams
e null-safe (Optional
) em Java, conforme mostrado abaixo ...
Streams (Java 8)
Para um programa de computador comum, geralmente você precisa trabalhar com uma lista de valores e realizar uma determinada transformação em cada valor. Antes do Java 8, você tinha que usar um loop for
para essa transformação, mas a partir de agora, você pode usar Streams da seguinte maneira:
Stream.of("Olá", "Ótimo")
.map(s -> s + " mundo")
.forEach(System.out::println);
Olá mundo
Ótimo mundo
A função map
recebe como entrada um lambda, que será aplicado a todos os elementos no fluxo.
Streams podem funcionar em List
, Set
e Map
(via transformação). Graças ao Streams, você pode se livrar de praticamente todos os loops em seu código!
Optional (Java 8)
Outro problema comum em Java eram as exceções de Null Pointer
. Portanto, Java introduziu Optional - envolve uma referência que pode ou não ser nula. A aplicação de atualizações a este Optional pode ser feita de maneira funcional:
Optional.of(new Random().nextInt(10))
.filter (i -> i % 2 == 0)
.map(i -> "O número é par: " + i)
.ifPresent(System.out::println);
O número é par: 6
No snippet acima criamos um número aleatório, o envolvemos em um objeto Optional
e, em seguida, se o número for par ele sera impresso na tela.
JShell (Java 9)
Finalmente temos um REPL para Java, e seu nome é JShell! Em poucas palavras JShell permite experimentar trechos de código Java sem escrever e compilar uma classe completa. Em vez disso, você pode executar um comando por vez e ver o resultado imediatamente. Aqui está um exemplo simples:
$ <JDK>/bin/jshell
jshell> System.out.println("Olá mundo!")
Olá Mundo!
Pessoas familiarizadas com linguagens interpretadas como JavaScript ou Python tiveram o prazer de um REPL por muito tempo, mas até agora, esse recurso estava faltando em Java. JShell permite definir variáveis, mas também entidades mais complexas, como métodos multilinhas, classes e executar loops. Além disso, o JShell oferece suporte ao preenchimento automático, o que é útil se você não souber os métodos exatos oferecidos por uma determinada classe Java.
Factory Methods para Collections imutáveis (Java 9)
A inicialização simples de List
está ausente em Java há muito tempo, mas esses tempos acabaram agora. Anteriormente, você tinha que fazer algo assim:
jshell> List<Integer> lista = Arrays.asList(1, 2, 3, 4)
lista ==> [1, 2, 3, 4]
Isso agora é simplificado da seguinte forma:
jshell> List<Integer> list = List.of(1, 2, 3, 4)
b ==> [1, 2, 3, 4]
Este método of(...)
existe para List, Set e Map. Todos eles criam um objeto imutável em apenas uma simples linha de código.
Inferencia de tipo com var (Java 10)
Java 10 introduziu a nova palavra-chave var que permite omitir o tipo de uma variável.
jshell> var x = new HashSet<String>()
x ==> []
jshell> x.add("maçã")
$ 1 ==> verdadeiro
No exemplo acima, o tipo de x pode ser inferido como HashSet
pelo compilador.
Esse recurso ajuda a reduzir o código e melhorar a legibilidade. No entanto, há algumas limitações para isso, você só pode usar var
dentro do corpo dos métodos, e o compilador inferirá o tipo em tempo de compilação, então tudo ainda está estaticamente tipado.
Compilação e execução de um arquivo com um único comando (Java 11)
Anteriormente, quando você escrevia um programa Java simples consistindo em um arquivo, era necessário primeiro compilar o arquivo com javac e depois executá-lo com java. No Java 11, você pode executar as duas etapas com um comando:
Main.java:
public class Main {
public static void main(String[] args) {
System.out.println("Olá mundo!");
}
}
$ java ./Main.java
Olá Mundo!
Para programas simples ou experimentos que consistem em apenas uma classe Java, esse recurso para executar arquivos de código-fonte único tornará sua vida mais fácil.
Expressão Switch (Java 12)
Java 12 nos trouxe expressões Switch. Aqui está uma demonstração rápida de como a expressão difere da antiga instrução switch
.
A antiga instrução switch
define o fluxo do programa:
jshell> var i = 3
jshell> String s;
jshell> switch (i) {
...> case 1: s = "um"; break;
...> case 2: s = "dois"; break;
...> case 3: s = "três"; break;
...> default: s = "número desconhecido";
...>}
jshell> s
s ==> "três"
Em contraste, a nova expressão switch retorna um valor:
jshell> var i = 3;
jshell> var x = switch(i) {
...> case 1 -> "um";
...> case 2 -> "dois";
...> case 3 -> "três";
...> default -> "número desconhecido";
...>};
x ==> "três"
Para resumir, a instrução switch
antiga define o fluxo do programa e a nova expressão switch retiorna um valor.
Observe que esta nova instrução switch
é uma espécie de função de mapeamento, há uma entrada (no caso i acima) e há uma saída (aqui x). Isso é um Pattern Matching que ajuda a tornar o Java mais compatível com os princípios de programação funcional. Uma instrução switch semelhante está disponível no Scala há algum tempo.
Algumas coisas a serem observadas:
Em vez de pontos duplos, usamos setas ->
Não há necessidade de break
O case default
pode ser omitido quando todos os casos possíveis são considerados
Para habilitar este recurso com Java 12, use --enable-preview --source 12
Strings multi-linhas (Java 13)
Você já teve que definir uma String
longa de várias linhas como JSON ou XML? Até agora, você provavelmente colocaria tudo em uma linha e usaria caracteres de nova linha "\n", mas isso torna a String
muito mais difícil de ler. Aí vem o Java 13 com String de várias linhas!
Por exemplo:
public class Main {
public static void main (String[] args) {
var s = """
{
"receita": "Vitamina de melancia",
"duração": "10 minutos",
"itens": ["melancia", "limão", "salsa"]
} """;
System.out.println(s);
}
}
Agora, executamos o método principal por meio de inicialização de arquivo único:
java --enable-preview --source 13 Main.java
{
"receita": "Vitamina de melancia",
"duração": "10 minutos",
"itens": ["melancia", "limão", "salsa"]
}
A String
resultante se estende por várias linhas, as aspas "" são deixadas intactas e até mesmo as tabulações são preservadas!
Classes de dados: Record (Java 14)
De todos os novos recursos neste artigo, este é provavelmente o que estou mais animado, finalmente existem classes de dados em Java! Essas classes são declaradas com a palavra-chave Record e têm getters
automáticos, um construtor
, o método equals()
, etc. Em suma, você pode se livrar de um grande pedaço de código!
jshell> record Employee(String nome, int idade, String departamento) {}
| created record Employee
jshell> var x = new Employee("Richard", 25, "DEV");
x ==> Employee[nome=Richard, idade=25, departamento=DEV]
jshell> x.nome()
$2 ==> "Richard"
Scala tem um recurso semelhante com case classes e Kotlin com data classes. Em Java, muitos desenvolvedores usam o Lombok até agora, que ofereceu praticamente os recursos que inspiraram Record
para o Java 14. Mais detalhes podem ser encontrados neste artigo do Baeldung.
instanceof sem Cast (Java 14)
As versões anteriores do Java já continham a palavra-chave instanceof
:
Object obj = new String("Olá");
if (obj instanceof String) {
System.out.println("Comprimento da string:" + ((String) obj).length());
}
A parte chata: primeiro verificamos se s é do tipo String
e, em seguida, transformamos novamente ela em String
para recuperar seu comprimento.
Agora, com o Java 14, o compilador é inteligente o suficiente para inferir o tipo automaticamente após o instanceof:
Object obj = new String("Olá");
if (obj instanceof String myStr) {
System.out.println("Comprimento da string:" + myStr.length());
}
Sealed classes (Java 15)
Com a palavra-chave Sealed, você pode restringir quais classes podem estender uma determinada classe ou interface. Aqui está um exemplo:
public sealed interface Fruta permits Banana, Pera {
String getName();
}
public final class Banana implements Fruit {
public String getName() { return "Banana"; }
}
public final class Pera implements Fruit {
public String getName() { return "Pera"; }
}
Então, como isso nos ajuda? Bem, agora você sabe quantas frutas existem. Este é realmente um passo importante na direção de pattern matching totalmente suportado, onde você pode tratar as classes
como Enums
. Este recurso Sealed
combina perfeitamente com a nova expressão de Switch
explicada anteriormente.
E com isso finalizamos aqui as atualizações que achei legal levantar, quaisquer dúvidas ou sugestões para que eu melhore nas postagens deixe um comentário.
E aí tem alguma outra atualização que acha legal adicionar?
Top comments (0)