O Java 8 foi lançado em 18 de março de 2014. Isso foi há muito tempo, mas ainda muitos projetos estão sendo executados no Java 8. Isso ocorre porque foi um lançamento importante com muitos recursos novos. Vamos dar uma olhada em todos os recursos emocionantes e principais do Java 8 com exemplos de código.
Visão geral rápida dos recursos do Java 8
Alguns dos recursos importantes do Java 8 são;
- método forEach() na interface Iterable
- métodos default e estáticos em Interfaces
- Interfaces Funcionais e Expressões Lambda
- API de Stream do Java para Operações de Dados em Massa em Coleções
- API de Tempo do Java
- melhorias na API de Coleções
- melhorias na API de Concorrência
- melhorias na API de E/S do Java
Vamos dar uma breve olhada nesses recursos do Java 8. Vou fornecer alguns trechos de código para entender melhor os recursos de maneira simples.
1. Método forEach() na interface Iterable
Sempre que precisamos percorrer uma coleção, precisamos criar um Iterador cujo único propósito é iterar sobre ela, e então temos lógica de negócio em um loop para cada um dos elementos na coleção. Podemos receber uma ConcurrentModificationException se o iterador não for usado corretamente.
O Java 8 introduziu o método forEach na interface java.lang.Iterable para que, ao escrevermos código, foquemos na lógica de negócio. O método forEach recebe um objeto java.util.function.Consumer como argumento, então ajuda a ter nossa lógica de negócio em um local separado que podemos reutilizar. Vamos ver o uso do forEach com um exemplo simples.
O número de linhas pode aumentar, mas o método forEach ajuda a ter a lógica para iteração e a lógica de negócio em lugares separados, resultando em uma maior separação de preocupações e código mais limpo.
2. Métodos padrão e estáticos em Interfaces
Se você ler detalhadamente os detalhes do método forEach, notará que ele está definido na interface Iterable, mas sabemos que interfaces não podem ter um corpo de método. A partir do Java 8, as interfaces foram aprimoradas para ter um método com implementação. Podemos usar a palavra-chave default
e static
para criar interfaces com implementação de método. A implementação do método forEach na interface Iterable é:
Sabemos que o Java não fornece herança múltipla em classes porque isso leva ao Problema do Diamante. Então, como isso será tratado com interfaces agora, já que as interfaces agora são semelhantes às classes abstratas?
A solução é que o compilador lançará uma exceção nesse cenário e teremos que fornecer a lógica de implementação na classe que implementa as interfaces.
Observe que ambas as interfaces têm um método comum log() com lógica de implementação.
Como você pode ver, Interface1
tem uma implementação de método estático que é usada no método MyClass.log()
. O Java 8 usa métodos default e estáticos extensivamente na API de Coleções e métodos padrão são adicionados para que nosso código permaneça compatível com versões anteriores.
Se alguma classe na hierarquia tiver um método com a mesma assinatura, então os métodos padrão se tornam irrelevantes. Object é a classe base, então se tivermos métodos padrão equals(), hashCode() na interface, eles se tornarão irrelevantes. É por isso que, para maior clareza, não é permitido que as interfaces tenham métodos padrão de Object.
Para detalhes completos das mudanças de interface no Java 8, por favor, leia Mudanças de interface do Java 8.
3. Interfaces Funcionais e Expressões Lambda
Se você observar o código de interface acima, você notará a anotação @FunctionalInterface. As interfaces funcionais são um novo conceito introduzido no Java 8. Uma interface com exatamente um método abstrato torna-se uma Interface Funcional. Não precisamos usar a anotação @FunctionalInterface para marcar uma interface como uma Interface Funcional. A anotação
@FunctionalInterface é uma facilidade para evitar a adição acidental de métodos abstratos nas interfaces funcionais. Você pode pensar nela como a anotação @Override e é uma prática recomendada utilizá-la. java.lang.Runnable com um único método abstrato run() é um ótimo exemplo de uma interface funcional.
Um dos principais benefícios da interface funcional é a possibilidade de usar expressões lambda para instanciá-las. Podemos instanciar uma interface com uma classe anônima, mas o código fica volumoso.
Uma vez que as interfaces funcionais têm apenas um método, as expressões lambda podem fornecer facilmente a implementação do método. Só precisamos fornecer argumentos do método e lógica de negócios. Por exemplo, podemos escrever a implementação acima usando uma expressão lambda como:
Se tivermos apenas uma declaração no método de implementação, também não precisamos de chaves. Por exemplo, a classe anônima Interface1 acima pode ser instanciada usando lambda da seguinte forma:
Portanto, expressões lambda são um meio de criar classes anônimas de interfaces funcionais facilmente. Não há benefícios em tempo de execução ao usar expressões lambda, então eu as usarei com cautela porque não me importo de escrever algumas linhas extras de código.
A new package java.util.function
has been added with bunch of functional interfaces to provide target types for lambda expressions and method references. Lambda expressions are a huge topic, I will write a separate article on that in the future.
Você pode ler o tutorial completo em Tutorial de Expressões Lambda do Java 8.
4. API de Fluxo Java para Operações em Massa em Coleções
A new java.util.stream
has been added in Java 8 to perform filter/map/reduce like operations with the collection. Stream API will allow sequential as well as parallel execution. This is one of the best features for me because I work a lot with Collections and usually with Big Data, we need to filter out them based on some conditions.
A interface Collection foi estendida com os métodos padrão stream() e parallelStream() para obter o Fluxo para execução sequencial e paralela. Vamos ver o uso deles com um exemplo simples.
Se você executar o código de exemplo acima, obterá uma saída como esta:
Observe que os valores de processamento paralelo não estão em ordem, então o processamento paralelo será muito útil ao trabalhar com coleções enormes.
Não é possível cobrir tudo sobre a API de Stream neste post, você pode ler tudo sobre a API de Stream em Tutorial de Exemplo da API de Stream do Java 8.
5. API de Tempo do Java
Sempre foi difícil trabalhar com Data, Hora e Fusos Horários em java. Não havia uma abordagem ou API padrão em java para data e hora em Java. Uma das boas adições no Java 8 é o pacote java.time
que vai simplificar o processo de trabalhar com tempo em java.
Apenas olhando para os pacotes da API de Tempo do Java, posso perceber que eles serão muito fáceis de usar. Ele tem alguns subpacotes java.time.format
que fornecem classes para imprimir e analisar datas e horas e java.time.zone
fornece suporte para fusos horários e suas regras.
A nova API de Tempo prefere enums em vez de constantes inteiras para meses e dias da semana. Uma das classes úteis é DateTimeFormatter
para converter objetos DateTime em strings. Para um tutorial completo, vá para Tutorial de Exemplo da API de Data e Hora do Java.
6. Melhorias na API de Coleções
Já vimos o método forEach() e a API Stream para coleções. Alguns novos métodos adicionados na API de Coleções são:
Iterator
método padrãoforEachRemaining(Consumer action)
para realizar a ação fornecida para cada elemento restante até que todos os elementos tenham sido processados ou a ação lance uma exceção.Collection
método padrãoremoveIf(Predicate filter)
para remover todos os elementos desta coleção que satisfaçam o predicado dado.Collection
métodospliterator()
retornando uma instância Spliterator que pode ser usada para percorrer elementos sequencial ou paralelamente.Map
métodosreplaceAll()
,compute()
,merge()
.- Melhoria de Desempenho para a classe HashMap com Colisões de Chaves
7. Melhorias na API de Concorrência
Algumas melhorias importantes na API concorrente são:
ConcurrentHashMap
métodos compute(), forEach(), forEachEntry(), forEachKey(), forEachValue(), merge(), reduce() e search().CompletableFuture
que pode ser explicitamente completado (definindo seu valor e status).Executors
métodonewWorkStealingPool()
para criar um pool de threads “work-stealing” usando todos os processadores disponíveis como seu nível de paralelismo alvo.
8. Melhorias no Java IO
Algumas melhorias de IO que conheço são:
Files.list(Path dir)
que retorna um Stream preenchido de forma preguiçosa, cujos elementos são as entradas no diretório.Files.lines(Path path)
que lê todas as linhas de um arquivo como um Stream.Files.find()
que retorna um Stream preenchido de forma preguiçosa com Path ao procurar arquivos em uma árvore de arquivos enraizada em um determinado arquivo inicial.BufferedReader.lines()
que retorna um Stream, cujos elementos são linhas lidas deste BufferedReader.
Melhorias Diversas na API Principal do Java 8
Algumas melhorias diversas na API que podem ser úteis são:
- ThreadLocal método estático withInitial(Supplier supplier) para criar instâncias facilmente.
- A interface Comparator foi estendida com muitos métodos padrão e estáticos para ordenação natural, ordem reversa, etc.
- Métodos min(), max() e sum() nas classes de envoltório Integer, Long e Double.
- Métodos logicalAnd(), logicalOr() e logicalXor() na classe Boolean.
- Método stream() de ZipFile para obter um Stream ordenado sobre as entradas do arquivo ZIP. As entradas aparecem no Stream na ordem em que aparecem no diretório central do arquivo ZIP.
- Vários métodos utilitários na classe Math.
- O comando
jjs
foi adicionado para invocar o Motor Nashorn. - O comando
jdeps
foi adicionado para analisar arquivos de classe. - A Ponte JDBC-ODBC foi removida.
- O espaço de memória PermGen foi removido
Isso é tudo para as características do Java 8 com programas de exemplo. Se eu perdi algumas características importantes do Java 8, por favor me avise através de comentários.
Source:
https://www.digitalocean.com/community/tutorials/java-8-features-with-examples