UPD. Hoje será o tão esperado lançamento do Java 14 - e mesmo que não seja o LTS - existem novos recursos suficientes. O Java 14 estará disponível em algumas horas - mas você pode conhecê-lo agora.
No Java 14, há mudanças suficientes, tanto no nível de escrita do código quanto no nível da API, GC e muitos outros mecanismos. Podemos dizer com certeza que, se você conhece alguns super-chips Kotlin ou Python - não se preocupe, com um alto grau de probabilidade, eles aparecerão em breve em Java. De qualquer forma, o release de hoje contém alguns deles. Mas as primeiras coisas primeiro.No Java 14, as seguintes inovações nos aguardam:- JEP 305. Atribuindo uma referência a um objeto que está sendo verificado através da instanceof.
- JEP 343. O empacotador jpackage (Incubadora).
- JEP 345. Alocação de memória baseada em NUMA para G1.
- JEP 349. Streaming de eventos através do JFR.
- JEP 352. Buffers de bytes mapeados imutáveis.
- JEP 358. Dicas sobre NullPointerException.
- Jep 359. Record.
- JEP 361. Alterne lambdas.
- JEP 362. As portas Solaris e SPARC agora estão obsoletas.
- JEP 363. Removendo o coletor de lixo Concurent Mark Sweep que foi marcado anteriormente como Descontinuado.
- JEP 364. Portando o ZGC no macOS.
- JEP 365. Portando o ZGC para o Windows.
- JEP 366. A combinação de ParallelScavenge + SerialOld GC agora está obsoleta.
- JEP 367. Removendo ferramentas e APIs do Pack200 (que foram marcadas como Descontinuadas no Java 11).
- JEP 368. Blocos de texto.
- JEP 370. API de acesso à memória externa (incubadora).
Vamos falar sobre cada melhoria, algumas das quais serão discutidas em mais detalhes.JEP 305. Atribuindo uma referência a um objeto verificado através da instância de
Considere a situação de verificar o tipo de um objeto por meio de instanceof. Se queremos personalizar explicitamente um objeto para o tipo necessário sem arriscar uma ClassCastException, primeiro precisamos ter certeza de que o objeto é do tipo que precisamos. private static void showNameIfToy(Object o) {
if (o instanceof Toy) {
Toy t = (Toy) o;
System.out.println("Toy's name: " + t.getName());
}
}
Neste exemplo, que ocorre, a propósito, o tempo todo, a) certificamos que temos um objeto do tipo desejado, b) atribuimos um link a ele, c) fazemos algo com ele, com base em nossa lógica. Na Oracle, ao que parece, eles viram um certo esplendor de código nessa construção específica e decidiram reduzi-lo em exatamente uma etapa. Agora você pode escrever assim: private static void showNameIfToy(Object o) {
if (o instanceof Toy t) {
System.out.println("Toy's name: " + t.getName());
}
}
Como tudo isso é realmente conveniente e útil, deixo para julgá-lo, leitor. Sim, de fato, essa construção dessa forma ocorre, provavelmente, em 99% dos casos associados à instância de e, talvez, a simplificação se enraíze (ou talvez não). O tempo vai dizer.JEP 343. O jpackage Packer (Incubadora)
Nós, os desenvolvedores, somos caras, você não vai nos assustar com a instalação de um dzharnik, mas e quanto a um usuário simples que não quer saber ao instalar a JVM que ele está instalado em outros 3 bilhões de máquinas, não quer saber sobre a plataforma cruzada Java, mas só quer cutucar 2 vezes o arquivo .exe se tiver Windows ou simplesmente arraste o aplicativo .app para a pasta Aplicativos, se houver uma papoula, e não o vaporize? Como criar todas as condições para os programadores para que eles empacotem seus aplicativos em "executáveis" familiares ao usuário final?Parece que a Oracle percebeu o problema e decidiu escrever um empacotador que empacotará imediatamente os aplicativos em um formato adequado para a plataforma:- Linux: deb e rpm
- macOS: pkg e dmg
- Windows: msi e exe
Parece algo como isto:$ jpackage --name myapp --input lib --main-jar main.jar --type exe
--name myapp - nome futuro do aplicativo--input lib - fonte do arquivo jar--main-jar main.jar - nome do arquivo que contém a classe principal--type exe - tipo no qual o aplicativo será empacotado.Após o empacotamento, você pode clicar duas vezes no myapp.exe (se você tiver o Windows) e instalá-lo como um aplicativo normal do Windows. A interface gráfica é fornecida pelo JavaFX.Vamos tentar criar esse aplicativo usando a plataforma Windows.Então, vamos pegar o projeto a partir daqui:https://github.com/promoscow/bouncerAo enviar uma solicitação GET, recebemos a mensagem: “Rejeição bem-sucedida” e carimbo de data e hora.Colocando um dzharnik. Como temos gradle, ele está na pasta build / libs.
Vá para a pasta build, insira o mínimo necessário de comandos:jpackage --name bouncer --input libs --main-jar bouncer.jar --type exe
Na verdade, temos um exe-shnik.
Nós cutucamos duas vezes no executável, a instalação usual do aplicativo ocorre.Uau!
O aplicativo foi instalado e está esperando nos bastidores.Em Arquivos de Programa, na pasta bouncer, você pode executar o bouncer.exe.
JEP 345. Alocação de memória alocada ao NUMA para G1
Existe um problema - NUMA, acesso não uniforme à memória, acesso desigual à memória. Em outras palavras, o acesso a soquetes remotos em máquinas de várias seções pode levar um tempo considerável, especialmente para o coletor de lixo G1. No Java 14, eles tentaram resolver esse problema da seguinte maneira: Oheap G1 é organizado como um conjunto de áreas de tamanho fixo. Uma região geralmente é uma coleção de páginas físicas, embora ao usar páginas grandes (via -XX: + UseLargePages), várias regiões possam formar uma página física.Se você adicionar o parâmetro + XX: + UseNUMA durante a inicialização da JVM, as regiões serão distribuídas uniformemente pelo número total de nós NUMA disponíveis.A Oracle promete que, embora essa abordagem não seja totalmente flexível, ela será aprimorada no futuro.JEP 349. Streaming de eventos através do JFR
Em Java, existe algo como JFR - Java Flight Recording - gravação de eventos em tempo real, que permite monitorar cerca de 500 variedades de eventos enquanto o aplicativo está em execução. O problema é que a maioria deles só pode ser visualizada nos logs. A melhoria oferecida pela Oracle é implementar um manipulador, por exemplo, uma função lambda que será chamada em resposta a um evento.Aqui está o que parece:try (var rs = new RecordingStream()) {
rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
rs.onEvent("jdk.CPULoad", event -> System.out.println(event.getFloat("machineTotal")));
rs.start();
}
Este evento a cada segundo exibe a carga do processador no console.
JEP 358. Dicas sobre NullPointerException
Outra conveniência óbvia, projetada para simplificar a busca por erros no código. Imagine uma construção - um planeta, existem muitos países no planeta, em todos os países existem muitas cidades.public class Planet {
private List<Country> countries;
}
public class Country {
private List<City> cities;
}
public class City {
private String name;
}
Decidimos exibir os códigos de hash de todas as cidades do planeta:planet.getCountries().forEach(c -> c.getCities().forEach(city -> city.hashCode()));
Mas eles não pensaram na inicialização obrigatória dos campos. E em algum momento eles receberam uma NullPointerException:Exception in thread "main" java.lang.NullPointerException
at ru.xpendence.jep_358_nullpointerexception.Main.main(Main.java:19)
Qual campo temos nulo? planeta? país? cidade ??? Nós não sabemos. Colocamos o ponto de interrupção na linha certa e, com um suspiro, nos degradamos.No Java 14, uma NullPointerException é mais informativa:Exception in thread "main" java.lang.NullPointerException: Cannot assign field "cities" because "countries" is null
at Main.main(Main.java:21)
...
E imediatamente tudo está claro. países é nulo.JEP 359. Record
Não é de admirar que a Oracle tenha alterado o ciclo de lançamento para seis meses. As mudanças tectônicas no setor de TI fazem com que até esses líderes se movam mais rapidamente. E se, por exemplo, Kotlin e Python no momento de sua aparência foram influenciados pelo Java (é o que a Wikipedia diz sobre o Python, de qualquer maneira), agora o Java está olhando para seus seguidores, por assim dizer. Sobre o Python, ele será menor, mas o seguinte recurso do Oracle foi analisado com precisão no Kotlin. É sobre classes de dados, que em Java agora são chamadas de registro.O que é uma classe de dados? Vamos escrever um POJO comum:public class Station {
private String name;
private Coordinates coordinates;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Coordinates getCoordinates() {
return coordinates;
}
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PlainStation that = (PlainStation) o;
return Objects.equals(name, that.name) &&
Objects.equals(coordinates, that.coordinates);
}
@Override
public int hashCode() {
return Objects.hash(name, coordinates);
}
@Override
public String toString() {
return "PlainStation{" +
"name='" + name + '\'' +
", coordinates=" + coordinates +
'}';
}
}
Aqui temos tudo: getters, setters, iguais, hashcode, toString ... Para, de alguma forma, livrar-se dessa desgraça, pessoas boas criaram Lombok.No Jetbrains, o problema foi resolvido de uma maneira mais radical - inventando classes de dados para o Kotlin. Essa classe com todos os métodos padrão se parece com isso:data class Station(val name: String, val coordinates: Coordinates)
E é isso. No Oracle, ao que parece, analisou esse design e fez exatamente o mesmo, apenas registrando:public record RecordStation(String name, List<Coordinates> coordinates) {}
Ele contém getters, setters, iguais, hashcode e toString padrão.Uma classe desse tipo já pode ser criada no IDEA 2020.1.Quais são as diferenças do POJO?
- O registro não pode ser herdado de nenhuma classe.
- O registro não pode ter outros campos do objeto, exceto aqueles declarados no construtor ao descrever a classe (sim, a propósito, esse é o construtor padrão). Estático - você pode.
- Os campos são implicitamente finais. Objetos são implicitamente finais. Com todas as consequências, como a impossibilidade de ser abstrato.
Acontece que essa é uma classe de dados imutável, não destinada a algumas ações lógicas complexas, mas destinada à transferência de dados, e isso é tudo.JEP 361. Switch Lambdas
Parece que a Oracle aceitou o interruptor firmemente. Antes do lançamento atual, era um design bastante volumoso e tinha a seguinte aparência: public static void translateDayOfWeekOld(String dayOfWeek) {
switch (dayOfWeek) {
case "MONDAY":
System.out.println("");
break;
case "TUESDAY":
System.out.println("");
break;
case "WEDNESDAY":
System.out.println("");
break;
case "THURSDAY":
System.out.println("");
break;
case "FRIDAY":
System.out.println("");
break;
case "SATURDAY":
System.out.println("");
break;
case "SUNDAY":
System.out.println("");
break;
default:
System.out.println("Day of week not found, try again with today day of week");
String displayName = LocalDate.now().getDayOfWeek().name();
translateDayOfWeek(displayName);
}
}
O processamento de uma condição requer pelo menos três linhas - caso, ação, interrupção. Agora, com a funcionalidade aprimorada do switch, podemos reduzir a construção acima para isso: public static void translateDayOfWeek(String dayOfWeek) {
switch (dayOfWeek) {
case "MONDAY" -> System.out.println("");
case "TUESDAY" -> System.out.println("");
case "WEDNESDAY" -> System.out.println("");
case "THURSDAY" -> System.out.println("");
case "FRIDAY" -> System.out.println("");
case "SATURDAY" -> System.out.println("");
case "SUNDAY" -> System.out.println("");
default -> {
System.out.println("Day of week not found, try again with today day of week");
String displayName = LocalDate.now().getDayOfWeek().name();
translateDayOfWeek(displayName);
}
}
}
Concordo, bastante compacto, elegante e com lambdas. Vale a pena, você decide.A propósito, a mudança de IDEA 2020.1, escrita de acordo com as regras antigas, sugere cuidadosamente reescrever de uma nova maneira.
JEP 362. Portas Solaris e SPARC agora obsoletas
Tudo é simples aqui. A Oracle decidiu que não valia a pena gastar recursos no suporte a portas Solaris e SPARC, e os funcionários liberados deveriam mudar para o desenvolvimento de novos recursos.JEP 363. Removendo o coletor de lixo Concurent Mark Sweep que foi marcado anteriormente como Descontinuado
A remoção do coletor de lixo do CMS foi discutida há dois anos, no nono lançamento. Durante esse período, dois coletores de lixo foram lançados - ZGC e Shenandoah. Ao mesmo tempo, nenhum dos colaboradores confiáveis da Oracle prestou atenção no suporte ao CMS.Em geral, o médico disse ao necrotério - depois ao necrotério.JEP 364, 365. Portando o ZGC no macOS e Windows
Normalmente, implantamos aplicativos nas plataformas Linux, mas, para o desenvolvimento local, geralmente usamos o Windows e o Mac. Para essas necessidades, o Java 14 portou o coletor de lixo ZGC para essas duas plataformas.JEP 366. Combinação ParallelScavenge + SerialOld GC agora descontinuada
Há uma configuração de coletor de lixo usada muito raramente - quando o jovem ParallelScavenge é combinado com o SerialOld. Por que isso é feito não está claro, pois ParallelScavenge é paralelo e SerialOld, pelo contrário, não é. A inclusão dessa combinação requer danças especiais com um pandeiro e requer muitos desenvolvedores de sangue. “A Oracle se preocupa com você”, por isso marca essa configuração como obsoleta e espera enviá-la em breve ao coletor de lixo do CMS.Vamos nos alegrar, irmãos.JEP 367. Removendo as ferramentas e APIs do Pack200 (que foram marcadas como Descontinuadas no Java 11)
A virada do pack200, unpack200 e API pack200 veio para um descanso bem merecido. E o motivo é a obsolescência desse empacotador. Era uma vez, quando a Internet era modem e sua velocidade era de 56k (lembram-se os boomers), o JDK teve que ser bombeado por horas. Foi inventado um empacotador que comprimiria o JDK melhor e reduziria o tempo de download. Além disso, eles poderiam compactar applets e aplicativos clientes. Mas o tempo passou e, nas velocidades atuais, o empacotador não é relevante.Os seguintes pacotes serão removidos:java.util.jar.Pack200java.util.jar.Pack200.Packerjava.util.jar.Pack200.Unpacker, bem como o módulo jdk.pack.JEP 368. Blocos de Texto
Ao mesmo tempo, o Java teve (entre uma meia dúzia de outras linguagens) um impacto no Python. Como o Python está rapidamente ganhando popularidade e avançando com confiança com outros líderes dos gráficos Java e C IT, não há nada de errado em espiar. Ao mesmo tempo, o Java 9 introduziu o JShell, muito semelhante ao pythonium Jupiter. E agora, chegou a hora dos blocos de texto.Quando precisamos escrever uma linha, escrevemos uma linha:String s = "";
Quando precisamos escrever uma string formatada, escrevemos algo como isto:String oldHtml = "<html>\n\t<body>\n\t\t<p>Hi all!</p>\n\t</body>\n</html>";
O texto é completamente ilegível. E assim, no Java 14, o problema está resolvido. Agora, usando aspas triplas, você pode escrever qualquer texto: String html = """
<html>
<body>
<p>Hi all!</p>
</body>
</html>
""";
É muito mais conveniente e legível. Podemos simplesmente copiar qualquer texto no código e não nos incomodar com guias e hífens. A beleza! Se precisarmos apenas transferir o texto para outra linha desse texto sem fazer hífen, podemos usar um novo literal - a barra invertida. Este símbolo generaliza que a transferência a seguir não é uma transferência. Exemplo: String text = """
\
, , \
\
. \
, , ! \
; \
\
.
""";
Conclusão:Os deuses ainda lhe deram dias dourados, noites douradas, e virgens lânguidas fixadas em seus olhos atentos. Toca, canta, ó amigos! Perca uma noite fugaz; E sua alegria pelo descuido Através das lágrimas eu sorrio.
JEP 370. API de acesso à memória externa (incubadora)
Acontece que um aplicativo acessa memória externa como Ignite, mapDB, memcached, etc. As APIs existentes para acessá-lo estão funcionando, mas a Oracle queria algo global. Então, as abstrações de MemorySegment, MemoryAddress e MemoryLayout apareceram. Enquanto o recurso estiver na incubadora, todos poderão se contentar com ByteBuffer, Unsafe e JNI.Conclusão
Não sei você, leitor, mas gosto do ciclo de seis meses para o qual a Oracle mudou desde o Java 9. Agora, a Oracle não define a tarefa de liberar versões absolutamente estáveis, mas a sofisticada javista não será difícil de manter a par da estabilidade de um recurso ou de outro, observando pelo desenvolvimento e teste de algo da incubadora. O idioma se tornou mais vibrante, mutável, inovações muito ousadas e empréstimos de outros idiomas começaram a aparecer nele. Sim, alguém não acompanha a oscilação dos lançamentos, mas nossa profissão é tal que precisamos acompanhar, portanto, quer desejemos ou não, encontramos o Java 14.Como sempre, estou anexando um projeto em um github com exemplos de código: [clique aqui]