En Java 9 Oracle mejoró concatenación de cadenas. Ahora "" + someBoolean
se convierte en invokedynamic
con StringConcatFabric.makeConcat
como método de arranque. Esa tela genera las clases en tiempo de ejecución que concatenan sus cuerdas. Quiero desactivar este comportamiento y vuelve a los constructor de cadena sencilla de edad.
Por lo que se supone que tiene javac bandera que hacer lo que quiera. Pero no puedo encontrarlo.
Hay dos partes en la función de concatenación de cadenas.
En tiempo de ejecución
En Java 9+, en tiempo de ejecución, concatenación de cadenas es controlado por la
StringConcatFactory
clase ( javadoc ). Eso es porquejavac
generainvokedynamic
código de bytes aStringConcatFactory::makeConcat
donde se necesite concatenación de cadenas.StringConcatFactory
define varias estrategias para el tiempo de ejecución de concatenación en la forma de unStrategy
enum ( código fuente ).Se puede cambiar la estrategia por defecto desde la línea de comandos de configuración
-Djava.lang.invoke.stringConcat
Para obtener el comportamiento de Java-8 en tiempo de ejecución, es necesario configurarlo para que
BC_SB
, acrónimo de "código de bytes, StringBuilder"Aquí están los otros valores, para lo completo:
/** * Bytecode generator, calling into {@link java.lang.StringBuilder}. */ BC_SB, /** * Bytecode generator, calling into {@link java.lang.StringBuilder}; * but trying to estimate the required storage. */ BC_SB_SIZED, /** * Bytecode generator, calling into {@link java.lang.StringBuilder}; * but computing the required storage exactly. */ BC_SB_SIZED_EXACT, /** * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}. * This strategy also tries to estimate the required storage. */ MH_SB_SIZED, /** * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}. * This strategy also estimate the required storage exactly. */ MH_SB_SIZED_EXACT, /** * MethodHandle-based generator, that constructs its own byte[] array from * the arguments. It computes the required storage exactly. */ MH_INLINE_SIZED_EXACT
En tiempo de compilación
Como Kayaman señala correctamente, la
StringConcatFactory
afecta el programa en tiempo de ejecución solamente. El código de bytes todavía contendrá unainvokedynamic
aStringConcatFactory
donde quiera cadenas se concatenan. Hay varias maneras de volver a las llamadasStringBuilder
:El enfoque más directo de desactivar este comportamiento es pasar la
--release=8
bandera a javac para forzar la generación de Java-8 Código compatibles. Sin embargo, esto no sólo afecta a la concatenación de cadenas.Una opción más específico es el control de concatenación específicamente, mediante el paso
-XDstringConcat=inline
.Tomemos este pedazo de código como un ejemplo:
public class Print { public static void main(String[] args) { String foo = "a"; String bar = "b"; System.out.println(foo+bar); } }
Si se compila sin ningún tipo de banderas, obtendremos:
public class Print { public Print(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 9: aload_1 10: aload_2 11: invokedynamic #5, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; 16: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 19: return }
Tenga en cuenta el
invokedynamic
amakeConcatWithConstants
.Sin embargo, si corremos
javac -XDstringConcat=inline Print.java
, nos pondremos esto:public class Print { public Print(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; 9: new #5 // class java/lang/StringBuilder 12: dup 13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 16: aload_1 17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 20: aload_2 21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 27: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 30: return }
Aquí la
String
concatenación se realiza mediante elStringBuilder
, al igual que en Java 8.