Ahora se lanzan nuevas versiones de Java cada seis meses. De vez en cuando, aparecen nuevas caracter铆sticas en ellos: var en Java 10, declaraciones de cambio en Java 14, registros y patrones en Java 16. Por supuesto, se han escrito muchos art铆culos y publicaciones de blogs sobre esto, y se han realizado muchos informes en conferencias. Sin embargo, result贸 que todos nos perdimos una actualizaci贸n de lenguaje muy interesante que sucedi贸 en Java 14: una actualizaci贸n del bucle for regular sobre un conjunto de enteros. El caso es que esta actualizaci贸n no ocurri贸 en el lenguaje, sino en la m谩quina virtual, pero influy贸 significativamente en c贸mo podemos programar en Java.
Recordemos el viejo bucle for:
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
Esta sintaxis tiene muchas desventajas. Primero, la variable de ciclo se menciona tres veces. Es muy f谩cil confundirse y mencionar la variable incorrecta en uno o dos lugares. En segundo lugar, tal variable no es efectivamente definitiva. No se pasar谩 expl铆citamente a lambdas o clases an贸nimas. Pero a煤n m谩s importante: no puede estar asegurado contra el cambio accidental de una variable dentro de un bucle. Leer el c贸digo tambi茅n es dif铆cil. Si el cuerpo del bucle es grande, no es tan f谩cil decir si tambi茅n cambia dentro del bucle, lo que significa que no est谩 claro, simplemente revisamos los n煤meros en orden o hacemos algo m谩s complicado. Tambi茅n hay errores potenciales si necesita cambiar la direcci贸n del bucle o activar el borde. Y parece anticuado.
Muchos lenguajes ya se han alejado del pesado legado de C y ofrecen una sintaxis m谩s moderna en la que simplemente especifica un rango de n煤meros. Por ejemplo, tome Kotlin:
for (x in 0 until 10) {
println(x)
}
: , , , . .
Java? , for-each, Java 5. :
/**
*
* @param fromInclusive ()
* @param toExclusive ( )
* @return Iterable, fromInclusive toExclusive.
*/
public static Iterable<Integer> range(int fromInclusive,
int toExclusive) {
return () -> new Iterator<Integer>() {
int cursor = fromInclusive;
public boolean hasNext() { return cursor < toExclusive; }
public Integer next() { return cursor++; }
};
}
rocket science, , . Java:
for (int i : range(0, 10)) { //
System.out.println(i);
}
. final, . . ? - . JMH-:
@Param({"1000"})
private int size;
@Benchmark
public int plainFor() {
int result = 0;
for (int i = 0; i < size; i++) {
result += i * i * i;
}
return result;
}
@Benchmark
public int rangeFor() {
int result = 0;
for (int i : range(0, size)) {
result += i * i * i;
}
return result;
}
, - , JIT- . , JIT . Java 8 :
Benchmark (size) Mode Cnt Score Error Units
BoxedRange.plainFor 1000 avgt 30 622.679 卤 7.286 ns/op
BoxedRange.rangeFor 1000 avgt 30 3591.052 卤 792.159 ns/op
range : 3,5 0,6 . -prof gc
, , rangeFor 13952 , plainFor . , , , 127 . Integer 128-999, 872 16 . , , Iterable, Iterator : (scalar replacement). .
, for , Java . Java:
: Java 14 range ! JIT- , , .
. Java 8 JVM -XX:+UnlockExperimentalVMOptions -XX:+AggressiveUnboxing
. , , :
Java 8-11 0,9 , 12 0,8, 13 . Java 14 , . , . , , .
? - Integer 127. valueOf ( Java 16):
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
, IntegerCache.low IntegerCache.high , . , , : . AggressiveUnboxing JIT- , , . , - :
Field field = Class.forName("java.lang.Integer$IntegerCache").getDeclaredField("cache");
field.setAccessible(true);
Integer[] arr = (Integer[]) field.get(null);
arr[130] = new Integer(1_000_000);
for (int i = 0; i < 10000; i++) {
int res = rangeFor();
if (res != -1094471800) {
System.out.println("oops! " + res + "; i = " + i);
break;
}
}
, , . Java if
. AggressiveUnboxing
oops! 392146832; i = 333
JIT- C2 rangeFor, , , , .
, Java 12 cmp r10d,7fh
, 127 (=0x7f). , Java 13. , , , - . , Java 12 rangeFor 8 , Java 13 16 , plainFor.
, : Java 14, . for (int i : range(0, 10))
Java for (int i = 0; i < 10; i++)
, .
Valhalla. Iterable<int>
, . , range . Iterable<Integer>
.