Artigos recentes
Inicio » Features
Mostrando postagens com marcador Features. Mostrar todas as postagens
Mostrando postagens com marcador Features. Mostrar todas as postagens
sábado, 17 de março de 2018
No artigo de hoje vamos falar não só de uma, mas sim de três versões do Java, a versão 9 (e os módulos), as melhorias da versão 10 e a futura versão 11. Este artigo é apenas para apresentar mudanças e não ensinar todos os aspectos delas.
Java 9
O Java 9 trouxe muitas melhorias, concatenação dinâmica de string, API de processos, cliente HTTP 2 (incubado, falarei disto também), Stack-Walking API, métodos privados em interfaces, métodos factory em coleções e o mais importante, sistema de módulos (Projeto Jigsaw).
Concatenação dinâmica de string
No Java 9, as concatenações de string, ou seja, isto:
"Seu nome é: " + person.getName() + ", e seu email: " + person.getEmail();
agora é compilado para um código dinâmico, ao invés de estático, mas o que muda com isto? Em relação a código Java, nada, você continua escrevendo a mesma coisa e recebendo os mesmo resultados, mas na prática, o desempenho deste código poderá ser melhorado com mudanças na máquina virtual Java, ao invés de apenas serem perceptíveis ao recompilar o código, como era antes do Java 9.
API de processos
No Java 9 agora temos uma nova API de processos, muitas coisas foram adicionadas nas classes existente e novas classes foram introduzidas, como a ProcessHandle. Com a nova API, você pode obter informações que antes não eram possíveis, como o id do processo (PID), processos filho, processo pai, argumentos, usuário, tempo na cpu, momento de inicialização, e até fechar o processo de forma natural ou forçada.
Cliente HTTP 2
O novo cliente de HTTP tem suporte ao HTTP/2, com autenticação, gerenciador de cookies, SSL, Proxy, classe para respostas de pedidos, etc... Veja a documentação da API.
Esta feature foi adicionada como incubação, o que isto quer dizer? É uma API que está em desenvolvimento mas foi exposta aos desenvolvedores por meio de um módulo de incubação, este módulo não é importado por padrão e as classes nele vão deixar de existir em futuras versões, seja porque foram descartadas, ou porque foram liberadas e movidas para outro modulo.
Stack-walking API
Esta nova API tem o propósito de tornar mais simples o ato de caminhar na stack, ou seja, conseguir inspecionar e encontrar os elementos da stack do Thread atual, os elementos estão ordenados do topo (sendo os primeiros elementos da stream) ao fundo (sendo os últimos elementos da stream).
Milling Coin e factory methods em coleções
Agora podemos declarar métodos privados em interfaces (teoricamente, já era possível desde o Java 8, com os lambdas dentro de métodos default), isto vai ajudar a diminuir códigos duplicados em métodos default em interfaces, permitindo a funcionalidade ser movida para um outro método sem ter que expor ele a quem irá consumir a API.
Agora também temos a possibilidade de anotar métodos privados com @SafeVarargs, usar o operador diamante (<>) em classes anonimas e também podemos usar variáveis efetivamente finais no try-with-resources, exemplo:
Resource res = openResource(...); Resource res2 = openResource(...); try (res; res2) { ... }
Além disso, o underscore ('_') agora é uma 'palavra' reservada, ou seja, você não poderá usar ele como identificador.
Agora também temos métodos factory em coleções, como List.of, Set.of, Map.of, mas tenha em mente que a coleção retornada por estes métodos são imutáveis, diferente das coleções retornadas pelo Collections, que normalmente são visualizações de outras coleções, visualizações nas quais, em alguns casos, seus métodos de modificação não refletem na listas originais, mas sim lançam uma exceção.
Spin-wait hints
Este recurso foi adicionado com o propósito de diminuir latência e consumo de energia em threads com spin loop. Spin loops são loops que são executados a todo momento enquanto esperam um trabalho ser finalizado por outro thread, sabe aquele while (foo.isRunning()) Thread.sleep(100);, então, ao invés de usar Thread.sleep ou algo similar (ou simplesmente só o while), você poderá usar Thread.onSpinWait, que faz com que o Thread espere alguma atividade terminar para continuar trabalhando, isto também abre portas para a JVM otimizar este código e determinar até quando o Thread deve aguardar.
Outras mudanças
Também houve várias outras mudanças, como G1GC tornar-se o coletor padrão, suporte a Unicode 7.0 ,8.0 e UTF-8 em arquivos de propriedades, Javadoc em HTML5, novo formato de string de versão, pipeline de anotações 2.0, e muitas outras que você pode ver aqui.
Sistema de módulos e o famoso Jigsaw
Finalmente chegamos aonde importa (na verdade todas as mudanças importam, mas essa importa mais): o sistema de módulos e o projeto Jigsaw. Com o sistema de módulos, partes do seu sistemas podem ser separadas em módulos, o que permite um melhor desenvolvimento, já que você poderá trabalhar com os módulos separadamente (até mesmo com equipes separadas) e testar seu sistema com estes módulos mesmo que os demais não estejam prontos (contanto que os módulos dependentes estejam prontos), também permite melhor escalabilidade, segurança (com encapsulamento forte) e que a JVM faça melhores otimizações de performance. Também tivemos a extensão do sistema de serviços, agora é possível prover e requisitar serviços por meio da declaração do módulo.
Também foram introduzidas novas ferramentas para construir uma máquina virtual com apenas alguns módulos (jlink), isto é perfeito para aplicações standalone, você não precisará mais ter uma aplicação com 190MB da JVM e 1MB da aplicação em si, você poderá ter uma JVM com a aplicação com apenas ≃20MB (diminui pela metade com compressão).
Também tivemos algumas mudanças que quebraram compatibilidade, como por exemplo, o fato do ClassLoader da aplicação não ser mais um URLClassLoader.
Você deve estar se perguntando, e o Jigsaw? (Ou não né). O Jigsaw é o projeto que engloba todo o sistema de módulos: a modularização da própria plataforma Java, as novas ferramentas, o encapsulamento das APIs internas, e etc...
Também foram introduzidas novas ferramentas para construir uma máquina virtual com apenas alguns módulos (jlink), isto é perfeito para aplicações standalone, você não precisará mais ter uma aplicação com 190MB da JVM e 1MB da aplicação em si, você poderá ter uma JVM com a aplicação com apenas ≃20MB (diminui pela metade com compressão).
Também tivemos algumas mudanças que quebraram compatibilidade, como por exemplo, o fato do ClassLoader da aplicação não ser mais um URLClassLoader.
Você deve estar se perguntando, e o Jigsaw? (Ou não né). O Jigsaw é o projeto que engloba todo o sistema de módulos: a modularização da própria plataforma Java, as novas ferramentas, o encapsulamento das APIs internas, e etc...
Mudanças importantes
Como disse anteriormente, o Java 10 não virá com o Valhalla, tivemos grandes mudanças não só no Java como também no modelo de lançamento, agora o Java será lançado de 6 em 6 meses com menores quantidades de novidades; e como o projeto Valhalla é um projeto que ainda não está pronto então ele não será incluído no Java 10, e talvez nem mesmo no 11 (provavelmente, com sorte, no 12 ou 13). Além disso, teremos suporte por tempo limitado, assim que sair o Java 10 (que está perto, 20/03), provavelmente não teremos mais atualizações para o Java 9 depois de um tempo, e quando sair o 11, não teremos mais atualizações para o 10, mas não se preocupe, o Java 8 é LTS, então terá suporte até 2019 ou 2020 (ou mais tempo), e o Java 11 será uma LTS também, porém o tempo de suporte ainda será divulgado em setembro¹.
E falando em suporte, a Oracle irá parar de dar suporte gratuito a Oracle JDK (hora de mudar para outra JDK com a OpenJDK, Eclipse OpenJ9, Zulu. Fique a vontade, ou você pode pagar pelo suporte da Oracle JDK).
Java 10
Temos a omissão do tipo de variável por meio do var, ele poderá ser usado na declaração de variáveis no lugar do tipo, e ficará a cargo do compilador inferir o tipo da variável, exemplo:
Predicate<User> isEmailValidated = User::isEmailValidated; var users = userManager.getOnlineUsers().stream().filter(isEmailValidated.negate()).collect(Collectors.toList()); // List<User> var names = users.stream().map(User::getUserName).collect(Collectors.toList()); // List<String>
Isto tornará os códigos mais legíveis (ou menos, depende de como você usar), porém note que para o caso do predicado foi necessário especificar o tipo explicitamente, isto também acontecerá com métodos genéricos, operador diamante ou array sem tipo explicito (tipo var x = {1, 2}; não é possível, mas var x = int[]{1, 2}; é possível). Entretanto, diferente de outras linguagens de programação aonde você pode utilizar outra palavra, como o val, para declaração de variável final, isto não foi incluso no Java 10, mesmo após altos números a favor.
Parecido com o invokedynamic, mas para constantes, removendo assim alguns limites do invokedynamic e dando mais suporte ainda a linguagens dinâmicas e abrindo mais portas para melhorias de desempenho (tanto da linguagem Java quando de linguagens dinâmicas).
Um novo coletor de lixo que não coleta lixo (que?), este coletor de lixo irá gerenciar o alocamento de memória, mas não irá reivindicar a memória, se o memória ficar cheia a JVM irá ser fechada. Este coletor poderá ser usado para testes de desempenho, já que ele irá afetar o minimo possível o desempenho (isso se não afetar nada), poderá ser usado para testar a pressão na memória, também para tarefas rápidas onde o tempo de vida da máquina virtual é pequeno, ou até mesmo para aplicações que são muito sensitivas a latência; eu que não gostaria do GC coletando o lixo bem na hora que o piloto automático deveria fazer uma curva, brincadeiras a parte, este novo coletor será muito útil para vários outros propósitos.
Para quem ta por fora, o Java EE não é mais um projeto da Oracle, agora é um projeto da Eclipse, e alias, foi renomeado para Jakarta EE.
Mas bom, o motivo da remoção não é esse, mas sim porque o Java EE era entregado juntamente ao Java SE apenas por conveniência, tanto Java EE como CORBA serão removidos, se você precisar deles, bom, já sabe, terá de incluir as bibliotecas deles na sua aplicação (alias, alguém usa ou tem interesse em usar CORBA?).
Outras mudanças
Tivemos também a interface do coletor de lixo, coleção de lixo totalmente paralela para o G1, compartilhamento dos dados de classe da aplicação, remoção do javah, etc.. Veja todas aqui.
O que esperar do Java 11
Com o Java 10 próximo de ser lançado (dia 20/03), já temos uma ideia do que teremos na versão subsequente:
Constantes dinâmicas
Parecido com o invokedynamic, mas para constantes, removendo assim alguns limites do invokedynamic e dando mais suporte ainda a linguagens dinâmicas e abrindo mais portas para melhorias de desempenho (tanto da linguagem Java quando de linguagens dinâmicas).
Epsilon - um novo coletor
Um novo coletor de lixo que não coleta lixo (que?), este coletor de lixo irá gerenciar o alocamento de memória, mas não irá reivindicar a memória, se o memória ficar cheia a JVM irá ser fechada. Este coletor poderá ser usado para testes de desempenho, já que ele irá afetar o minimo possível o desempenho (isso se não afetar nada), poderá ser usado para testar a pressão na memória, também para tarefas rápidas onde o tempo de vida da máquina virtual é pequeno, ou até mesmo para aplicações que são muito sensitivas a latência; eu que não gostaria do GC coletando o lixo bem na hora que o piloto automático deveria fazer uma curva, brincadeiras a parte, este novo coletor será muito útil para vários outros propósitos.
Remoção dos módulos Java EE e CORBA
Para quem ta por fora, o Java EE não é mais um projeto da Oracle, agora é um projeto da Eclipse, e alias, foi renomeado para Jakarta EE.
Mas bom, o motivo da remoção não é esse, mas sim porque o Java EE era entregado juntamente ao Java SE apenas por conveniência, tanto Java EE como CORBA serão removidos, se você precisar deles, bom, já sabe, terá de incluir as bibliotecas deles na sua aplicação (alias, alguém usa ou tem interesse em usar CORBA?).
Sintaxe para variáveis locais de lambdas
Eis algo que incrementará a sintaxe Java, mas nada muito grande, esta mudança permitirá a utilização do var nas declarações de variáveis de lambdas, permitindo assim a adição de anotações sem perder a brevidade das declarações lambdas. Exemplo:
Function<String, Integer> toInteger = (@NotNull var s) -> Integer.parseInt(s);
Bom era apenas isso, se houver mais novidade com relação ao Java 11 farei um outro artigo. Obrigado por ler :D Atualizações do mundo Java
domingo, 15 de maio de 2016
Project Valhalla
Para quem não conhece, o projeto Valhalla visa melhorar os genéricos da linguagem Java. Como a própria página do projeto diz, ele não irá trazer os genéricos reificados para o Java, o objetivo principal é permitir que possamos utilizar primitivos nos genéricos.
É inevitável que, com a evolução da JVM seja necessário termos uma espécie de unificação entre Referencias e Valores (primitivos) no sistema de genéricos do Java, já que, cada vez os genéricos estão mais presentes na linguagem, como por exemplo, nas classes funcionais.
Atualmente, os genéricos só aceitam Referencias, e isto faz com que, se você quiser passar os tipos primitivos, você irá informar o tipo Wrapped (Integer, Character, Short, etc), e quando passar os valores, a JVM irá fazer boxing e unboxing, e como na maioria das vezes utilizamos primitivos, a JVM terá um grande problema com o desempenho. A solução atual desenvolvida pela equipe para a área funcional, foi criar classes funcionais que aceitassem primitivos (IntUnaryOperator, DoubleUnaryOperator), porém, em uma linguagem orientada a objetos, esta não é a melhor solução, sem considerar que, o método destas classes são: applyAsInt, applyAsDouble, etc.
A proposta atual da equipe do Valhalla é: manter o type erasure para os genericos de Referencia, e criar uma nova classe em runtime para os primitivos, esta é uma boa solução, mas ainda é apenas o começo.
Até o momento, a parte mais importante já foi implementada, a geração de classe para os primitivos e a possibilidade de usa-los nos genéricos.
Para que isto pudesse ser possivel era necessário que algumas instruções fossem substituidas por outras, por exemplo, quando se trata de um objeto é utilizado 'aload', 'astore', porém, quando se trata de um primitivo, é necessário usar por exemplo, 'iload', 'dload', etc, uma para cada primitivo. A proposta do modelo 3 era criar novas instruções que pudessem chamar outras instruções baseadas no tipo armazenado no 'constant pool' (cabeçalho da classe aonde ficam muitas das informações) das classes, sendo elas 'vreturn', 'vload', 'vstore', etc... que referenciam uma posição do 'constant pool', atualmente é este que esta sendo implementado no projeto.
Veja um exemplo abaixo:
Minha classe:
Para que isto pudesse ser possivel era necessário que algumas instruções fossem substituidas por outras, por exemplo, quando se trata de um objeto é utilizado 'aload', 'astore', porém, quando se trata de um primitivo, é necessário usar por exemplo, 'iload', 'dload', etc, uma para cada primitivo. A proposta do modelo 3 era criar novas instruções que pudessem chamar outras instruções baseadas no tipo armazenado no 'constant pool' (cabeçalho da classe aonde ficam muitas das informações) das classes, sendo elas 'vreturn', 'vload', 'vstore', etc... que referenciam uma posição do 'constant pool', atualmente é este que esta sendo implementado no projeto.
Veja um exemplo abaixo:
Minha classe:
A palavra 'any' será a nova palavra reservada do Java, que indica que este genérico poderá receber qualquer coisa, não só Referencias, mas também tipos primitivos. Também será inserida duas novas palavras reserdas, ref e val, ref será somente para referencias, e val para os futuros 'Value Types' e os primitivos. Quando compilada, serão geradas duas classes, a MinhaClasse e MinhaClasse$$any.
A classe MinhaClasse implementará a classe MinhaClasse$$any, a qual até o momento é só uma representação, não tem nenhum elemento dentro dela, somente algumas informações.
Agora vamos ver o que ocorre quando chamarmos esta classe com dois tipos distintos, uma int, e outra String.
Agora, quando executarmos este código, quando você instanciar a classe pedindo que o genérico seja int, a JVM irá gerar uma classe que também implementa MinhaClasse$$any que aceita int, e com um método getValue que retorna int, esta classe se chamara MinhaClasse$${I} (sendo I a representação de int). No segundo caso, a JVM continuará fazendo o mesmo que faz atualmente, inferindo os tipos, não irá gerar nenhuma classe.
A geração de classes fica a cargo de um "especializador", o mesmo faz logging dizendo que especializou a classe.
Vamos dar uma olhada no bytecode agora?
Na primeira declaração, vemos que o compilador gera uma chamada para uma classe chamada MinhaClass<I>, qual não existe em tempo de compilação, em em tempo de execução será gerada, assim permitindo que ela seja chamada ser dar erro de "ClassNotFound", também é chamado o construtor (I)V, que está presente na classe gerada, mas não na classe que escrevemos (a que escrevemos tem o constructor descrito como '(Ljava/lang/Object;)V' (MinhaClasse(Object)), qual se pode observar mais abaixo após '// String X'
O compilador gera o código desta forma pois, durante a compilação, não é possível chamar classes inexistente (o compilador oficial não permite), mas é possível sim, chamar métodos ou classes que não existem durante a compilação, contanto que elas existam durante a execução da aplicação.
Os obstaculos
Por mais que tenha muita coisa pronta, ainda não está completo, é necessário ainda correções no sistema de Arrays (proposta Arrays 2.0), Arrays de genéricos ainda precisam ser Object (o método toArray do List & Stream por exemplo, que aceita T[], só irá aceitar arrays de objetos, não os de int), melhorias de desempenho e refinamentos, também tem o problema com a compatibilidade, que é o maior obstáculo atual.
Fiquem ligados, mais noticias postarei no blog.
Assinar:
Postagens (Atom)