Membuka kemasan di Java modern

Sekarang versi baru Java dirilis setiap enam bulan. Dari waktu ke waktu, fitur-fitur baru muncul di dalamnya: var di Java 10, ekspresi switch di Java 14, catatan dan pola di Java 16. Tentu saja, banyak artikel, posting blog telah ditulis tentang ini, dan banyak laporan telah dibuat di konferensi. Namun, ternyata, kita semua melewatkan satu peningkatan bahasa yang sangat keren yang terjadi di Java 14 - peningkatan ke perulangan for reguler melalui satu set bilangan bulat. Faktanya adalah bahwa peningkatan ini tidak terjadi dalam bahasa, tetapi di mesin virtual, tetapi secara signifikan memengaruhi cara kita dapat memprogram di Java.





Mari kita ingat loop lama yang bagus:





for (int i = 0; i < 10; i++) {
  System.out.println(i);
}
      
      



Sintaks ini memiliki banyak kekurangan. Pertama, variabel loop disebutkan tiga kali. Sangat mudah untuk menjadi bingung dan menyebutkan variabel yang salah di satu atau dua tempat. Kedua, variabel seperti itu belum final secara efektif. Anda tidak dapat secara eksplisit meneruskannya ke lambda atau kelas anonim. Tetapi yang lebih penting: Anda tidak dapat diasuransikan terhadap perubahan variabel secara tidak sengaja di dalam loop. Membaca kodenya juga sulit. Jika badan perulangan besar, tidak mudah untuk mengatakan apakah itu juga berubah di dalam perulangan, yang berarti tidak jelas, kita hanya memutar angkanya secara berurutan atau melakukan sesuatu yang lebih rumit. Ada juga potensi kesalahan jika Anda perlu mengubah arah loop atau mengaktifkan perbatasan. Dan itu terlihat kuno.





Banyak bahasa telah menjauh dari warisan berat C dan menawarkan sintaks yang lebih modern di mana Anda cukup menentukan kisaran angka. Misalnya, ambil 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>



.








All Articles