Olá novamente. Como já escrevemos, na próxima semana um novo grupo de treinamento no curso
"Java Developer" começará, de acordo com a tradição estabelecida, compartilharemos com você a tradução de material interessante sobre o tema.
A partir do JDK 9, a concatenação de cadeias passou por mudanças significativas.O JEP 280 (“Indify Concatenation String”) foi implementado como parte do
JDK 9 e, de acordo com a seção Summary: “Altera a sequência do bytecode da concatenação da string gerada por
javac para usar chamadas
dinâmicas invocadas para funções da biblioteca JDK.” O efeito que isso tem na concatenação de cadeias de caracteres em Java é mais facilmente percebido observando a saída
javap de classes que usam concatenação de cadeias que foram compiladas no JDK antes do JDK 9 e depois do JDK 9.

Para a primeira demonstração, uma classe Java simples chamada “HelloWorldStringConcat” será usada.
package dustin.examples; import static java.lang.System.out; public class HelloWorldStringConcat { public static void main(final String[] arguments) { out.println("Hello, " + arguments[0]); } }
A seguir, é apresentada uma comparação das diferenças da saída -verbose javap para o método
main(String)
da classe HelloWorldStringConcat ao compilar com o JDK 8
(AdoptOpenJDK) e o JDK 11
(Oracle OpenJDK) . Eu destaquei algumas diferenças importantes.
Saída JDK 8 javap Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringConcat.class Last modified Jan 28, 2019; size 625 bytes MD5 checksum 3e270bafc795b47dbc2d42a41c8956af Compiled from "HelloWorldStringConcat.java" public class dustin.examples.HelloWorldStringConcat minor version: 0 major version: 52 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
Saída javap JDK 11 Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringConcat.class Last modified Jan 28, 2019; size 908 bytes MD5 checksum 0e20fe09f6967ba96124abca10d3e36d Compiled from "HelloWorldStringConcat.java" public class dustin.examples.HelloWorldStringConcat minor version: 0 major version: 55 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=1, args_size=1 0: getstatic #2
A seção "Descrição" no
JEP 280 descreve esta diferença: "A idéia é substituir toda a dança de junção StringBuilder por uma chamada
invokedynamic
simples para
java.lang.invoke.StringConcatFactory , que assumirá valores que precisam ser mesclados". A mesma seção mostra uma comparação semelhante da saída compilada para um exemplo de concatenação de string semelhante.
A saída compilada com o JDK 11 para concatenação fácil não é apenas menos linhas do que a saída do JDK 8; ele também tem menos operações "caras". Potenciais aprimoramentos de desempenho podem ser alcançados devido ao fato de que não há necessidade de agrupar tipos primitivos e você não precisa criar muitos objetos adicionais. Um dos principais motivos dessa mudança foi "estabelecer as bases para a criação de manipuladores de concatenação de string otimizados que são implementados sem a necessidade de alterar o compilador Java para bytecode" e "ativar otimizações futuras de concatenação de string sem alterações adicionais no bytecode gerado pelo javac. "
Há uma conseqüência interessante disso em termos de uso de
StringBuffer (que
acho difícil encontrar um bom uso para qualquer maneira) e
StringBuilder . No JEP 280, “Non-Goal” declarou não “introduzir novas APIs para String e / ou StringBuilder que poderiam ajudar a criar estratégias de tradução mais eficientes”. Nesse sentido, para concatenação simples de strings, como no exemplo no início deste post, o uso explícito de StringBuilder e StringBuffer praticamente exclui o compilador de usar o recurso introduzido no
JEP 280 , que discutiremos neste post.
As duas listagens a seguir mostram implementações semelhantes do aplicativo simples mostrado acima, mas em vez de concatenar cadeias, elas usam StringBuilder e StringBuffer, respectivamente. Quando o javap -verbose é executado para essas classes após serem compiladas com o JDK 8 e com o JDK 11, não há diferenças significativas nos métodos principais (String []).
O uso explícito de StringBuilder no JDK 8 e JDK 11 é o mesmo package dustin.examples; import static java.lang.System.out; public class HelloWorldStringBuilder { public static void main(final String[] arguments) { out.println(new StringBuilder().append("Hello, ").append(arguments[0]).toString()); } }
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringBuilder.class Last modified Jan 28, 2019; size 627 bytes MD5 checksum e7acc3bf0ff5220ba5142aed7a34070f Compiled from "HelloWorldStringBuilder.java" public class dustin.examples.HelloWorldStringBuilder minor version: 0 major version: 52 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringBuilder.class Last modified Jan 28, 2019; size 627 bytes MD5 checksum d04ee3735ce98eb6237885fac86620b4 Compiled from "HelloWorldStringBuilder.java" public class dustin.examples.HelloWorldStringBuilder minor version: 0 major version: 55 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
O uso explícito de StringBuffer no JDK 8 e JDK 11 é o mesmo package dustin.examples; import static java.lang.System.out; public class HelloWorldStringBuffer { public static void main(final String[] arguments) { out.println(new StringBuffer().append("Hello, ").append(arguments[0]).toString()); } }
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringBuffer.class Last modified Jan 28, 2019; size 623 bytes MD5 checksum fdfb90497db6a3494289f2866b9a3a8b Compiled from "HelloWorldStringBuffer.java" public class dustin.examples.HelloWorldStringBuffer minor version: 0 major version: 52 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringBuffer.class Last modified Jan 28, 2019; size 623 bytes MD5 checksum e4a83b6bb799fd5478a65bc43e9af437 Compiled from "HelloWorldStringBuffer.java" public class dustin.examples.HelloWorldStringBuffer minor version: 0 major version: 55 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=4, locals=1, args_size=1 0: getstatic #2
JDK 8 e JDK 11 manipulando concatenações de seqüência de caracteres em loopPara o exemplo final de alterações no JEP 280 em ação, uso um código de exemplo que pode quebrar a suscetibilidade de alguns desenvolvedores Java e concatenar seqüências de caracteres em um loop. Lembre-se de que este é apenas um exemplo ilustrativo e tudo ficará bem, mas não tente repeti-lo em casa.
package dustin.examples; import static java.lang.System.out; public class HelloWorldStringConcatComplex { public static void main(final String[] arguments) { String message = "Hello"; for (int i=0; i<25; i++) { message += i; } out.println(message); } }
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringConcatComplex.class Last modified Jan 30, 2019; size 766 bytes MD5 checksum 772c4a283c812d49451b5b756aef55f1 Compiled from "HelloWorldStringConcatComplex.java" public class dustin.examples.HelloWorldStringConcatComplex minor version: 0 major version: 52 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: ldc #2
Classfile /C:/java/examples/helloWorld/classes/dustin/examples/HelloWorldStringConcatComplex.class Last modified Jan 30, 2019; size 1018 bytes MD5 checksum 967fef3e7625965ef060a831edb2a874 Compiled from "HelloWorldStringConcatComplex.java" public class dustin.examples.HelloWorldStringConcatComplex minor version: 0 major version: 55 . . . public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: ldc #2
Na apresentação
“Chega de java.lang.String para se enforcar ...” , o Dr.
Heinz M. Kabutz e
Dmitry Vyazelenko discutem as alterações feitas na concatenação de strings Java e as resumem brevemente, “+ more não compilado no StringBuilder ". No slide Lessons from Today, eles afirmam: “Use + em vez de StringBuilder sempre que possível” e “Recompile classes para Java 9+.”
As alterações implementadas no JDK 9 com o
JEP 280 , "permitirão otimizar a concatenação de cadeias no futuro, sem exigir alterações adicionais no bytecode gerado pelo javac". Curiosamente, foi anunciado recentemente que o JEP 348 (“Java Compiler Intrinsics for JDK APIs”) agora é candidato ao JEP, e seu objetivo é usar uma abordagem semelhante para compilar os métodos
String :: format e
Objects::hash
.
O que você acha que é um artigo útil? Estamos aguardando seus comentários e convidamos todos para um
dia aberto no curso Java Developer, que será realizado em 25 de março pelo diretor geral da OTUS -
Vitaly Chibrikov .