Agora, novas versões do Java são lançadas a cada seis meses. De vez em quando, novos recursos aparecem neles: var no Java 10, alternar expressões no Java 14, registros e padrões no Java 16. Claro, muitos artigos, postagens de blog foram escritos sobre isso e muitos relatórios foram feitos em conferências. Descobrimos, no entanto, que todos nós perdemos uma atualização de linguagem muito legal que aconteceu no Java 14 - uma atualização do loop for regular sobre um conjunto de inteiros. O fato é que essa atualização não aconteceu na linguagem, mas na máquina virtual, mas influenciou significativamente a forma como podemos programar em Java.
Vamos lembrar o bom e velho loop for:
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
Essa sintaxe tem muitas desvantagens. Primeiro, a variável de loop é mencionada três vezes. É muito fácil se confundir e mencionar a variável errada em um ou dois lugares. Em segundo lugar, essa variável não é efetivamente final. Não será explicitamente passado para lambdas ou classes anônimas. Mas ainda mais importante: você não pode estar seguro contra a alteração acidental de uma variável dentro de um loop. Ler o código também é difícil. Se o corpo do loop for grande, não é tão fácil dizer se ele também muda dentro do loop, o que significa que não está claro, apenas contornamos os números em ordem ou fazemos algo mais complicado. Também podem ocorrer erros se você precisar alterar a direção do loop ou ativar a borda. E parece antiquado.
Muitas linguagens já se afastaram do legado pesado de C e oferecem uma sintaxe mais moderna, onde você simplesmente especifica um intervalo de números. Por exemplo, veja 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>
.