Java 14: Rekam, contoh yang lebih ringkas, pembungkus jpackage, beralih lambdas dan blok teks

UPD. Hari ini akan menjadi rilis Java 14 yang telah lama ditunggu-tunggu - dan bahkan jika bukan LTS - ada cukup banyak fitur baru di dalamnya. Java 14 akan tersedia dalam beberapa jam - tetapi Anda dapat mengetahuinya sekarang.



Di Java 14, ada cukup banyak perubahan, baik di level kode penulisan, dan di level API, GC dan banyak engine hood lainnya. Kita dapat mengatakan dengan pasti bahwa jika Anda tahu tentang beberapa chip super Kotlin atau Python - jangan khawatir, dengan tingkat probabilitas tinggi mereka akan segera muncul di Jawa. Bagaimanapun, rilis hari ini berisi beberapa di antaranya. Tetapi hal pertama yang pertama.

Di Jawa 14, inovasi berikut menunggu kami:

  • JEP 305. Menetapkan referensi ke objek yang sedang diperiksa melalui instanceof.
  • JEP 343. Packer jpackage (Inkubator).
  • JEP 345. Alokasi memori berbasis NUMA untuk G1.
  • JEP 349. Streaming acara melalui JFR.
  • JEP 352. Buffer Byte Dipetakan yang Tidak Berubah.
  • JEP 358. Kiat tentang NullPointerException.
  • Jep 359. Rekam.
  • JEP 361. Ganti lambdas.
  • JEP 362. Port Solaris dan SPARC sekarang sudah tidak digunakan lagi.
  • JEP 363. Menghapus Tanda Konkur Penyapu sampah yang sebelumnya ditandai sebagai sudah usang.
  • JEP 364. Memasang ZGC di macOS.
  • JEP 365. Porting ZGC ke Windows.
  • JEP 366. Kombinasi ParallelScavenge + SerialOld GC sekarang sudah ditinggalkan.
  • JEP 367. Menghapus alat dan API dari Pack200 (yang ditandai sebagai Deprecated back in Java 11).
  • JEP 368. Blok Teks.
  • JEP 370. API Akses Memori Eksternal (Inkubator).

Mari kita bicara tentang setiap peningkatan, beberapa di antaranya akan dibahas lebih terinci.

JEP 305. Menetapkan referensi ke objek diperiksa melalui instanceof




Pertimbangkan situasi memeriksa jenis objek melalui instanceof. Jika kita ingin secara eksplisit menyesuaikan objek ke tipe yang diperlukan tanpa mempertaruhkan ClassCastException, pertama-tama kita perlu memastikan bahwa objek tersebut adalah tipe yang kita butuhkan.

    private static void showNameIfToy(Object o) {
        if (o instanceof Toy) {  //,    -  Toy
            Toy t = (Toy) o;  //  
            System.out.println("Toy's name: " + t.getName());  //-   
        }
    }

Dalam contoh ini, yang terjadi, omong-omong, sepanjang waktu, kami a) memastikan bahwa kami memiliki objek dengan tipe yang diinginkan, b) menetapkan tautan ke sana, c) melakukan sesuatu dengannya, berdasarkan logika kami. Di Oracle, tampaknya, mereka melihat kemegahan kode tertentu dalam konstruksi khusus ini, dan memutuskan untuk menguranginya tepat satu langkah. Sekarang Anda dapat menulis seperti ini:

    private static void showNameIfToy(Object o) {
        if (o instanceof Toy t) {  //      
            System.out.println("Toy's name: " + t.getName());  //     
        }
    }

Bagaimana semua ini benar-benar nyaman dan bermanfaat, saya tinggalkan untuk menghakimi Anda, pembaca. Ya, memang, konstruksi ini dalam bentuk ini terjadi, mungkin, dalam 99% kasus yang terkait dengan instanceof, dan, mungkin, penyederhanaan akan berakar (atau mungkin tidak). Waktu akan menjawab.

JEP 343. Packer jpackage (Inkubator)




Kami, para pengembang, adalah orang-orang yang tertembak, Anda tidak akan membuat kami takut dengan pemasangan dzharnik, tetapi bagaimana dengan pengguna sederhana yang tidak ingin tahu ketika memasang JVM yang diinstal pada 3 miliar mesin lain, tidak ingin tahu tentang Java lintas-platform, tetapi hanya ingin menyodok 2 kali file .exe jika memiliki Windows, atau cukup seret aplikasi .app ke folder Aplikasi, jika memiliki poppy, dan jangan mengukusnya? Bagaimana cara membuat semua kondisi untuk programmer sehingga mereka mengemas aplikasi mereka dalam "executable" yang akrab bagi pengguna akhir?

Tampaknya Oracle menyadari masalahnya dan memutuskan untuk menulis sebuah paket yang akan segera mengemas aplikasi dalam format yang sesuai untuk platform:

  • Linux: deb dan rpm
  • macOS: pkg dan dmg
  • Windows: msi dan exe

Itu terlihat seperti ini:

$ jpackage --name myapp --input lib --main-jar main.jar --type exe

--name myapp - nama masa depan aplikasi
--input lib - sumber arsip jar -
main-jar main.jar - nama arsip yang berisi kelas utama
--tipe exe - tipe di mana aplikasi akan dikemas.

Setelah pengemasan, Anda dapat mengklik dua kali pada myapp.exe (jika Anda memiliki Windows) dan menginstalnya sebagai aplikasi windows biasa. Antarmuka grafis disediakan oleh JavaFX.

Mari kita coba membangun aplikasi semacam itu menggunakan platform Windows.

Jadi, mari kita ambil proyek dari sini:
https://github.com/promoscow/bouncer
Saat mengirim permintaan GET, kita mendapatkan pesan: "Bouncing berhasil" dan cap waktu.

Menempatkan dzharnik. Karena kita memiliki gradle, itu ada di folder build / libs.



Buka folder build, masukkan perintah minimum yang diperlukan:

jpackage --name bouncer --input libs --main-jar bouncer.jar --type exe

Kami benar-benar mendapatkan exe-shnik.



Kami menyodok dua kali dalam executable, instalasi aplikasi yang biasa terjadi.
Wow!



Aplikasi telah diinstal dan menunggu di sayap.
Di Program Files, di folder bouncer, Anda dapat menjalankan bouncer.exe.



JEP 345. Alokasi memori yang dialokasikan NUMA untuk G1


Ada masalah seperti itu - NUMA, Non-Uniform Memory Access, Akses memori tidak merata. Dengan kata lain, akses ke soket jarak jauh di mesin multi-bagian dapat memakan waktu cukup lama, terutama untuk pengumpul sampah G1. Di Jawa 14, mereka mencoba memecahkan masalah ini sebagai berikut:

Tumpukan G1 disusun sebagai seperangkat area ukuran tetap. Suatu wilayah biasanya merupakan kumpulan halaman fisik, meskipun saat menggunakan halaman besar (via -XX: + UseLargePages), beberapa wilayah dapat membuat satu halaman fisik.

Jika Anda menambahkan + XX: + Parameter UseNUMA selama inisialisasi JVM, wilayah akan didistribusikan secara merata atas jumlah total NUMA node yang tersedia.

Oracle berjanji bahwa meskipun pendekatan ini tidak sepenuhnya fleksibel, mereka akan memperbaikinya di masa depan.

JEP 349. Streaming Acara Melalui JFR


Ada hal seperti itu di Jawa seperti JFR - Java Flight Recording - merekam peristiwa dengan cepat, yang memungkinkan Anda untuk memantau sekitar 500 jenis acara saat aplikasi sedang berjalan. Masalahnya adalah kebanyakan dari mereka hanya dapat dilihat di log. Peningkatan yang ditawarkan oleh Oracle adalah untuk mengimplementasikan handler, misalnya, fungsi lambda yang akan dipanggil sebagai respons terhadap suatu peristiwa.

Begini tampilannya:

try (var rs = new RecordingStream()) {
  rs.enable("jdk.CPULoad").withPeriod(Duration.ofSeconds(1));
  rs.onEvent("jdk.CPULoad", event -> System.out.println(event.getFloat("machineTotal")));
  rs.start();
}

Acara ini setiap detik menampilkan beban prosesor ke konsol.



JEP 358. Kiat tentang NullPointerException


Kenyamanan lain yang jelas, dirancang untuk menyederhanakan pencarian kesalahan dalam kode. Bayangkan sebuah konstruksi - sebuah planet, ada banyak negara di planet ini, di setiap negara ada banyak kota.

public class Planet {

    private List<Country> countries;
    //...
}

public class Country {

    private List<City> cities;
    //...
}

public class City {

    private String name;
    //...
}

Kami memutuskan untuk menampilkan kode hash dari semua kota di planet ini:

planet.getCountries().forEach(c -> c.getCities().forEach(city -> city.hashCode()));

Tetapi mereka tidak berpikir tentang inisialisasi wajib bidang. Dan pada titik tertentu mereka mendapat NullPointerException:

Exception in thread "main" java.lang.NullPointerException
	at ru.xpendence.jep_358_nullpointerexception.Main.main(Main.java:19)

Kolom mana yang kita miliki null? planet? negara? kota ??? Kami tidak tahu. Kami meletakkan breakpoint di garis kanan dan, sambil mendesah, pergi merendahkan.

Di Java 14, NullPointerException lebih informatif:

Exception in thread "main" java.lang.NullPointerException: Cannot assign field "cities" because "countries" is null
     at Main.main(Main.java:21)
     ...

Dan segera semuanya jelas. negara adalah nol.

JEP 359. Rekam




Tidak heran Oracle mengubah siklus rilis ke siklus enam bulan. Pergeseran tektonik dalam industri TI membuat pemimpin seperti itu bergerak lebih cepat. Dan jika, misalnya, Kotlin dan Python pada saat kemunculannya dipengaruhi oleh Java (toh begitulah yang dikatakan Wikipedia tentang Python), sekarang Java sedang melihat para pengikutnya. Tentang Python akan lebih rendah, tetapi fitur berikut dari Oracle justru mencari di Kotlin. Ini tentang kelas data, yang di Jawa sekarang disebut record.

Apa itu kelas data? Mari kita menulis POJO reguler:

public class Station {

    private String name;
    private Coordinates coordinates;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Coordinates getCoordinates() {
        return coordinates;
    }

    public void setCoordinates(Coordinates coordinates) {
        this.coordinates = coordinates;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        PlainStation that = (PlainStation) o;
        return Objects.equals(name, that.name) &&
                Objects.equals(coordinates, that.coordinates);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, coordinates);
    }

    @Override
    public String toString() {
        return "PlainStation{" +
                "name='" + name + '\'' +
                ", coordinates=" + coordinates +
                '}';
    }
}

Di sini kita memiliki semuanya secara berurutan - getter, setter, equals, hashcode, toString ... Agar entah bagaimana menyingkirkan aib ini, orang-orang baik datang dengan Lombok.

Di Jetbrains, masalahnya diselesaikan pada satu waktu dengan cara yang lebih radikal - dengan menciptakan kelas data untuk Kotlin. Kelas seperti itu dengan semua metode standar terlihat seperti ini:

data class Station(val name: String, val coordinates: Coordinates)

Dan itu dia. Di Oracle, tampaknya, melihat desain ini dan melakukan persis sama, hanya merekam:

public record RecordStation(String name, List<Coordinates> coordinates) {}

Ini berisi getter standar, setter, sama dengan, kode hash dan toString.
Kelas jenis ini sudah dapat dibuat di IDEA 2020.1.

Apa perbedaan dari POJO?


  • Catatan tidak dapat diwarisi dari kelas mana pun.
  • Record tidak dapat memiliki bidang objek lain, kecuali untuk yang dideklarasikan di konstruktor ketika menggambarkan kelas (ya, ini adalah konstruktor default, by the way). Statis - Anda bisa.
  • Fields secara implisit bersifat final. Objek secara implisit bersifat final. Dengan semua konsekuensi, seperti ketidakmungkinan menjadi abstrak.

Ternyata ini adalah kelas data yang tidak dapat diubah, tidak dimaksudkan untuk beberapa tindakan logis yang rumit dengannya, tetapi dimaksudkan untuk transfer data, dan hanya itu.

JEP 361. Ganti Lambdas




Tampaknya Oracle telah mengambil alih dengan erat. Sebelum rilis saat ini, itu adalah desain yang agak besar, dan terlihat seperti ini:

    public static void translateDayOfWeekOld(String dayOfWeek) {
        switch (dayOfWeek) {
            case "MONDAY":
                System.out.println("");
                break;
            case "TUESDAY":
                System.out.println("");
                break;
            case "WEDNESDAY":
                System.out.println("");
                break;
            case "THURSDAY":
                System.out.println("");
                break;
            case "FRIDAY":
                System.out.println("");
                break;
            case "SATURDAY":
                System.out.println("");
                break;
            case "SUNDAY":
                System.out.println("");
                break;
            default:
                System.out.println("Day of week not found, try again with today day of week");
                String displayName = LocalDate.now().getDayOfWeek().name();
                translateDayOfWeek(displayName);
        }
    }

Memproses satu kondisi membutuhkan setidaknya tiga baris - case, action, break. Sekarang, dengan fungsionalitas sakelar yang ditingkatkan, kita dapat mempersingkat konstruksi di atas menjadi ini:

    public static void translateDayOfWeek(String dayOfWeek) {
        switch (dayOfWeek) {
            case "MONDAY" -> System.out.println("");
            case "TUESDAY" -> System.out.println("");
            case "WEDNESDAY" -> System.out.println("");
            case "THURSDAY" -> System.out.println("");
            case "FRIDAY" -> System.out.println("");
            case "SATURDAY" -> System.out.println("");
            case "SUNDAY" -> System.out.println("");
            default -> {
                System.out.println("Day of week not found, try again with today day of week");
                String displayName = LocalDate.now().getDayOfWeek().name();
                translateDayOfWeek(displayName);
            }
        }
    }

Setuju, cukup ringkas, modis dan dengan lambdas. Apakah itu layak, Anda yang memutuskan.

Omong-omong, alihkan IDEA 2020.1, yang ditulis sesuai dengan aturan lama, dengan hati-hati menyarankan penulisan ulang dengan cara baru.



JEP 362. Port Solaris dan SPARC Sekarang Tidak Digunakan lagi


Semuanya sederhana di sini. Oracle memutuskan bahwa itu tidak layak menghabiskan sumber daya untuk mendukung port Solaris dan SPARC, dan karyawan yang dibebaskan harus beralih ke pengembangan fitur baru.

JEP 363. Menghapus Tanda Konkur Penyapu sampah yang sebelumnya ditandai sebagai sudah usang


Penghapusan pemulung sampah CMS dibahas dua tahun lalu, dalam rilis ke-9. Selama waktu ini, dua pemulung keluar - ZGC dan Shenandoah. Pada saat yang sama, tidak ada kontributor Oracle yang dapat dipercaya memperhatikan dukungan CMS.

Secara umum, dokter berkata kepada kamar mayat - kemudian ke kamar mayat.

JEP 364, 365. Porting ZGC pada macOS dan Windows


Kami biasanya menggunakan aplikasi pada platform Linux, tetapi untuk pengembangan lokal kami sering menggunakan Windows dan Mac. Untuk kebutuhan ini, Java 14 mem-porting pengumpul sampah ZGC ke dua platform ini.

JEP 366. ParallelScavenge + SerialOld GC Combination Now Deprecated


Ada konfigurasi pengumpul sampah yang sangat jarang digunakan - ketika ParallelScavenge muda digabungkan dengan SerialOld. Mengapa ini dilakukan tidak jelas, karena ParallelScavenge paralel, dan SerialOld, sebaliknya, tidak. Dimasukkannya kombinasi ini membutuhkan tarian khusus dengan rebana dan membutuhkan banyak pengembang darah. "Oracle peduli dengan Anda," sehingga menandai konfigurasi ini sebagai usang dan berharap untuk segera mengirimkannya ke pengumpul sampah CMS.

Mari kita bersukacita, saudara.

JEP 367. Menghapus alat dan API Pack200 (yang ditandai sebagai Sudah usang di Jawa 11)


Pergantian pack200, unpack200 dan API pack200 datang untuk istirahat yang memang layak. Dan alasannya adalah usang packer ini. Sekali waktu, ketika Internet adalah modem dan kecepatannya adalah 56rb (ingat boomer), JDK harus dipompa keluar selama berjam-jam. Packer diciptakan yang akan mengkompres JDK lebih baik dan mengurangi waktu pengunduhan. Juga, mereka dapat mengompres applet dan aplikasi klien. Tetapi waktu berlalu, dan pada kecepatan saat ini, pengepak tidak relevan.

Paket-paket berikut akan dihapus:

java.util.jar.Pack200
java.util.jar.Pack200.Packer
java.util.jar.Pack200.Unpacker

serta modul jdk.pack.

JEP 368. Blok Teks




Pada suatu waktu, Java memiliki (di antara satu setengah lusin bahasa lain) berdampak pada Python. Karena Python dengan cepat mendapatkan popularitas dan mendorong dengan penuh percaya diri dengan pemimpin lain dari Java dan C IT chart, tidak ada yang salah dengan mengintipnya. Pada suatu waktu, Java 9 memperkenalkan JShell, sangat mirip dengan pythonium Jupiter. Dan sekarang, saatnya telah tiba untuk blok teks.

Ketika kita perlu menulis satu baris, kita menulis satu baris:

String s = "";

Ketika kita perlu menulis string yang diformat, kita menulis sesuatu seperti ini:
String oldHtml = "<html>\n\t<body>\n\t\t<p>Hi all!</p>\n\t</body>\n</html>";

Teks ini benar-benar tidak dapat dibaca. Jadi, di Jawa 14 masalah terpecahkan. Sekarang, menggunakan tanda kutip tiga, Anda dapat menulis teks apa pun:

        String html = """
                      <html>
                          <body>
                              <p>Hi all!</p>
                          </body>
                      </html>
                      """;

Ini jauh lebih nyaman dan mudah dibaca. Kami hanya dapat menyalin teks apa pun ke dalam kode dan tidak repot dengan tab dan tanda hubung. Kecantikan! Jika kita hanya perlu mentransfer teks ke baris lain dalam teks seperti itu tanpa membuat tanda hubung, kita dapat menggunakan literal baru - garis miring terbalik. Simbol ini menggeneralisasi bahwa pemindahan yang mengikutinya bukan pemindahan. Contoh:

        String text = """
                    \
                 ,  , \
                     \
                   . \
                , ,  ! \
                  ; \
                    \
                   .
                """;

Kesimpulan:

Para dewa masih memberimu hari-hari emas, malam-malam emas, dan para gadis yang lesu memusatkan perhatian padamu. Mainkan, bernyanyi, hai teman-teman! Kehilangan malam yang singkat; Dan kegembiraan Anda karena kecerobohan Melalui air mata aku tersenyum.


JEP 370. API Akses Memori Eksternal (Inkubator)


Kebetulan aplikasi mengakses memori eksternal seperti Ignite, mapDB, memcached, dll. API yang ada untuk mengaksesnya cukup berfungsi, tetapi Oracle menginginkan sesuatu yang global. Jadi abstraksi dari MemorySegment, MemoryAddress dan MemoryLayout muncul. Sementara fitur ada di inkubator, dan semua orang masih bisa puas dengan ByteBuffer, Unsafe dan JNI.

Kesimpulan


Saya tidak tahu tentang Anda, pembaca, tapi saya suka siklus rilis enam bulan yang telah diubah Oracle sejak Java 9. Sekarang Oracle tidak menetapkan tugas untuk merilis rilis yang benar-benar stabil, tetapi javista yang canggih tidak akan sulit untuk mengikuti kestabilan satu fitur atau yang lain, mengamati untuk pengembangan mereka dan menguji sesuatu dari inkubator. Bahasa telah menjadi lebih bersemangat, dapat berubah, inovasi yang sangat berani dan pinjaman dari bahasa lain mulai muncul di dalamnya. Ya, seseorang tidak mengikuti kerlipan rilis, tetapi profesi kami sedemikian rupa sehingga kami perlu mengikuti, jadi apakah kami menginginkannya atau tidak, kami bertemu dengan Java 14.

Seperti biasa, saya melampirkan proyek pada github dengan contoh kode: [klik di sini]

All Articles