JavaRush /Blog Java /Random-MS /Ciri Java 8 – Panduan Terbaik (Bahagian 2)
0xFF
Tahap
Донецк

Ciri Java 8 – Panduan Terbaik (Bahagian 2)

Diterbitkan dalam kumpulan
Bahagian kedua terjemahan artikel Java 8 Features – The ULTIMATE Guide . Bahagian pertama ada di sini (pautan mungkin berubah). Ciri Java 8 – Panduan Terbaik (Bahagian 2) - 1

5. Ciri baharu dalam perpustakaan Java 8

Java 8 telah menambah banyak kelas baharu dan melanjutkan kelas sedia ada untuk menyokong konkurensi moden, pengaturcaraan berfungsi, tarikh/masa dan banyak lagi dengan lebih baik.

5.1. Kelas Pilihan

NullPointerException yang terkenal adalah punca kegagalan aplikasi Java yang paling biasa. Lama dahulu, projek cemerlang Google Guava dibentangkan Optionalsebagai penyelesaian NullPointerException, dengan itu menghalang kod daripada dicemari oleh semakan nol, dan akibatnya menggalakkan penulisan kod yang lebih bersih. Kelas Guava yang diilhamkan oleh Google Optionalkini merupakan sebahagian daripada Java 8. OptionalIa hanyalah bekas: ia boleh mengandungi nilai atau beberapa jenis Т, atau hanya menjadi nol. Ia menyediakan banyak kaedah berguna supaya semakan nol yang jelas tidak lagi wajar. Rujuk kepada dokumentasi rasmi untuk maklumat lebih terperinci. Mari kita lihat dua contoh kecil penggunaan Optional: dengan dan tanpa null.
Optional<String> fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
Kaedah isPresent()mengembalikan benar jika contoh Optionalmengandungi nilai bukan nol dan palsu sebaliknya. Kaedah ini orElseGet()mengandungi mekanisme sandaran untuk keputusan jika Optionalia mengandungi null, menerima fungsi untuk menjana nilai lalai. Kaedah peta () mengubah nilai semasa Optionaldan mengembalikan kejadian baharu Optional. Kaedah ini orElse()serupa dengan orElseGet(), tetapi bukannya fungsi ia memerlukan nilai lalai. Berikut adalah output program ini:
Full Name is set? false
Full Name: [none]
Hey Stranger!
Mari kita lihat contoh lain:
Optional<String> firstName = Optional.of( "Tom" );
System.out.println( "First Name is set? " + firstName.isPresent() );
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) );
System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
System.out.println();
Hasilnya akan menjadi seperti ini:
First Name is set? true
First Name: Tom
Hey Tom!
Untuk maklumat lebih terperinci, sila rujuk kepada dokumentasi rasmi .

5.2. Aliran

Stream API ( ) yang baru ditambahjava.util.stream memperkenalkan pengaturcaraan gaya berfungsi sebenar dalam Java. Ia setakat ini merupakan tambahan yang paling komprehensif kepada perpustakaan Java dan membolehkan pembangun Java menjadi lebih cekap dan juga membolehkan mereka mencipta kod yang cekap, bersih dan ringkas. Stream API menjadikan koleksi pemprosesan lebih mudah (tetapi tidak terhad kepada mereka, seperti yang akan kita lihat nanti). Mari kita ambil kelas mudah sebagai contoh Task.
public class Streams  {
    private enum Status {
        OPEN, CLOSED
    };

    private static final class Task {
        private final Status status;
        private final Integer points;

        Task( final Status status, final Integer points ) {
            this.status = status;
            this.points = points;
        }

        public Integer getPoints() {
            return points;
        }

        public Status getStatus() {
            return status;
        }

        @Override
        public String toString() {
            return String.format( "[%s, %d]", status, points );
        }
    }
}
Tugas mempunyai beberapa rasa (atau pseudo-kesukaran) dan boleh sama ada BUKA atau TUTUP . Mari perkenalkan koleksi kecil masalah untuk dimainkan.
final Collection<Task> tasks = Arrays.asList(
    new Task( Status.OPEN, 5 ),
    new Task( Status.OPEN, 13 ),
    new Task( Status.CLOSED, 8 )
);
Soalan pertama yang ingin kami ketahui ialah berapa banyak mata yang terkandung dalam tugas OPEN pada masa ini? Sebelum Java 8, penyelesaian biasa untuk ini adalah menggunakan iterator foreach. Tetapi dalam Java 8, jawapannya ialah aliran: jujukan elemen yang menyokong operasi agregat berjujukan dan selari.
// Подсчет общего количества очков всех активных задач с использованием sum()
final long totalPointsOfOpenTasks = tasks
    .stream()
    .filter( task -> task.getStatus() == Status.OPEN )
    .mapToInt( Task::getPoints )
    .sum();

System.out.println( "Total points: " + totalPointsOfOpenTasks );
Dan output konsol akan kelihatan seperti:
Total points: 18
Mari lihat apa yang berlaku di sini. Pertama, pengumpulan tugas ditukar kepada perwakilan penstriman. Operasi kemudian filtermenapis semua tugas dengan status TUTUP . Dalam langkah seterusnya, operasi mapToIntmenukar aliran Tasks kepada aliran Integers menggunakan kaedah Task::getPointsuntuk setiap contoh Task. Akhirnya, semua mata dijumlahkan menggunakan kaedah sum, yang memberikan hasil akhir. Sebelum beralih ke contoh seterusnya, terdapat beberapa nota tentang benang yang perlu diingat (perincian lanjut di sini ). Operasi streamdibahagikan kepada operasi pertengahan dan akhir . Operasi perantaraan mengembalikan aliran baharu. Mereka sentiasa malas; apabila melakukan operasi perantaraan seperti filter, mereka sebenarnya tidak melakukan penapisan, sebaliknya mencipta strim baharu, yang, apabila selesai, mengandungi unsur strim asal yang sepadan dengan predikat yang diberikan. Operasi terhingga , seperti forEachdan sum, boleh melalui aliran untuk menghasilkan hasil atau kesan sampingan. Setelah operasi akhir selesai, strim dianggap digunakan dan tidak boleh digunakan lagi. Dalam hampir semua kes, operasi tamat cenderung untuk melengkapkan traversal mereka melalui sumber data asas. Satu lagi ciri penting benang ialah sokongan untuk proses selari di luar kotak. Mari kita lihat contoh ini, yang mencari jumlah markah semua masalah.
// Calculate total points of all tasks
final double totalPoints = tasks
   .stream()
   .parallel()
   .map( task -> task.getPoints() ) // or map( Task::getPoints )
   .reduce( 0, Integer::sum );

System.out.println( "Total points (all tasks): " + totalPoints );
Ini sangat serupa dengan contoh pertama, kecuali kami cuba memproses semua tugas secara selari dan mengira hasil akhir menggunakan kaedah reduce. Berikut ialah output konsol:
Total points (all tasks): 26.0
Selalunya terdapat keperluan untuk mengumpulkan elemen mengikut kriteria tertentu. Contoh menunjukkan bagaimana urutan boleh membantu dengan ini.
// Группировка задач по их статусу
final Map<Status, List<Task>> map = tasks
    .stream()
    .collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );
Output konsol adalah seperti berikut:
{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}
Untuk menyelesaikan dengan contoh masalah, mari kita mengira peratusan keseluruhan (atau berat) setiap masalah dalam koleksi berdasarkan jumlah mata:
// Подсчет веса каждой задачи (How процент от общего количества очков)
final Collection<String> result = tasks
    .stream()                                        // Stream<String>
    .mapToInt( Task::getPoints )                     // IntStream
    .asLongStream()                                  // LongStream
    .mapToDouble( points -> points / totalPoints )   // DoubleStream
    .boxed()                                         // Stream<Double>
    .mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream
    .mapToObj( percentage -> percentage + "%" )      // Stream<String>
    .collect( Collectors.toList() );                 // List<String>

System.out.println( result );
Output konsol akan menjadi seperti ini:
[19%, 50%, 30%]
Akhir sekali, seperti yang kami nyatakan sebelum ini, Stream API bukan hanya untuk koleksi Java. Operasi I/O biasa, seperti membaca fail teks baris demi baris, adalah calon yang sangat baik untuk menggunakan pemprosesan strim. Berikut adalah contoh kecil untuk membuktikannya.
final Path path = new File( filename ).toPath();
try( Stream<String> lines = Files.lines( path, StandardCharsets.UTF_8 ) ) {
    lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
}
Kaedah onConsole, yang dipanggil pada utas, mengembalikan utas yang setara dengan pengendali peribadi tambahan. Pengendali persendirian dipanggil apabila kaedah close()dipanggil pada benang. API Strim bersama lambdas dan kaedah rujukan bersama kaedah lalai dan statik dalam Java 8 adalah jawapan kepada paradigma pembangunan perisian moden. Untuk maklumat lebih terperinci, sila rujuk kepada dokumentasi rasmi .

5.3. API Tarikh/Masa (JSR 310)

Java 8 membawa wajah baharu kepada pengurusan tarikh dan masa dengan menyediakan API Tarikh dan Masa baharu (JSR 310) . Manipulasi tarikh dan masa adalah salah satu titik kesakitan yang paling teruk untuk pembangun Java. Standard java.util.Dateberikut java.util.Calendartidak secara amnya memperbaiki keadaan (malah mungkin menjadikannya lebih mengelirukan). Begitulah Joda-Time dilahirkan : alternatif API tarikh/masa yang hebat untuk Java . API Tarikh/Masa baharu dalam Java 8 (JSR 310) sangat dipengaruhi oleh Joda-Time dan mengambil yang terbaik daripadanya. Pakej baharu java.timemengandungi semua kelas untuk tarikh, masa, tarikh/masa, zon masa, tempoh dan manipulasi masa . Reka bentuk API mengambil kebolehubahan dengan sangat serius: perubahan tidak dibenarkan (pengajaran sukar dipelajari daripada java.util.Calendar). Jika pengubahsuaian diperlukan, contoh baharu kelas yang sepadan akan dikembalikan. Mari lihat kelas utama dan contoh penggunaannya. Kelas pertama Clock, yang menyediakan akses kepada segera semasa, tarikh dan masa menggunakan zon waktu. Clockboleh digunakan sebagai ganti System.currentTimeMillis()dan TimeZone.getDefault().
// Получить системное время How смещение UTC
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );
Contoh output konsol:
2014-04-12T15:19:29.282Z
1397315969360
Kelas baharu lain yang akan kami lihat ialah LocaleDatedan LocalTime. LocaleDatemengandungi hanya bahagian tarikh tanpa zon waktu dalam sistem kalendar ISO-8601. Oleh itu, LocalTimeia mengandungi hanya sebahagian daripada kod masa>.
// получить местную date и время время
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );

System.out.println( date );
System.out.println( dateFromClock );

// получить местную date и время время
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );

System.out.println( time );
System.out.println( timeFromClock );
Contoh output konsol:
2014-04-12
2014-04-12
11:25:54.568
15:25:54.568
LocalDateTimemenggabungkan LocaleDatedan LocalTimedan mengandungi tarikh dan masa, tetapi tiada zon waktu, dalam sistem kalendar ISO-8601. Contoh mudah diberikan di bawah.
// Get the local date/time
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );

System.out.println( datetime );
System.out.println( datetimeFromClock );
Contoh output konsol:
2014-04-12T11:37:52.309
2014-04-12T15:37:52.309
Sekiranya anda memerlukan tarikh/masa untuk zon waktu tertentu, ZonedDateTime. Ia mengandungi tarikh dan masa dalam sistem kalendar ISO-8601. Berikut ialah beberapa contoh untuk zon waktu yang berbeza.
// Получение даты/времени для временной зоны
final ZonedDateTime zonedDatetime = ZonedDateTime.now();
final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );

System.out.println( zonedDatetime );
System.out.println( zonedDatetimeFromClock );
System.out.println( zonedDatetimeFromZone );
Contoh output konsol:
2014-04-12T11:47:01.017-04:00[America/New_York]
2014-04-12T15:47:01.017Z
2014-04-12T08:47:01.017-07:00[America/Los_Angeles]
Dan akhirnya, mari kita lihat kelas Duration: rentang masa dalam saat dan nanosaat. Ini menjadikan pengiraan antara dua tarikh sangat mudah. Mari lihat bagaimana untuk melakukan ini:
// Получаем разницу между двумя датами
final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );

final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );
System.out.println( "Duration in hours: " + duration.toHours() );
Contoh di atas mengira tempoh (dalam hari dan jam) antara dua tarikh, 16 April 2014 dan 16 April 2015 . Berikut ialah contoh output konsol:
Duration in days: 365
Duration in hours: 8783
Tanggapan keseluruhan tarikh/masa baharu dalam Java 8 adalah sangat, sangat positif. Sebahagiannya kerana perubahan itu berdasarkan asas yang diuji pertempuran (Joda-Time), sebahagiannya kerana kali ini isu itu dipertimbangkan semula dengan serius dan suara pembangun didengari. Untuk butiran, sila rujuk kepada dokumentasi rasmi .

5.4. Enjin JavaScript Nashorn

Java 8 dilengkapi dengan enjin JavaScript Nashorn baharu , yang membolehkan anda membangunkan dan menjalankan jenis aplikasi JavaScript tertentu pada JVM. Enjin JavaScript Nashorn hanyalah satu lagi pelaksanaan javax.script.ScriptEngine yang mengikut set peraturan yang sama untuk membenarkan Java dan JavaScript berinteraksi. Berikut adalah contoh kecil.
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName( "JavaScript" );

System.out.println( engine.getClass().getName() );
System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );
Contoh output konsol:
jdk.nashorn.api.scripting.NashornScriptEngine
Result: 2

5.5. Pangkalan64

Akhirnya, sokongan untuk pengekodan Base64 menemui jalan masuk ke perpustakaan standard Java dengan keluaran Java 8. Ia sangat mudah untuk digunakan, contohnya menunjukkan ini.
package com.javacodegeeks.java8.base64;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Base64s {
    public static void main(String[] args) {
        final String text = "Base64 finally in Java 8!";

        final String encoded = Base64
            .getEncoder()
            .encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
        System.out.println( encoded );

        final String decoded = new String(
            Base64.getDecoder().decode( encoded ),
            StandardCharsets.UTF_8 );
        System.out.println( decoded );
    }
}
Output konsol program menunjukkan kedua-dua teks yang dikodkan dan dinyahkod:
QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!
Terdapat juga kelas untuk pengekod/penyahkod mesra URL, serta pengekod/penyahkod mesra MIME ( Base64.getUrlEncoder()/ Base64.getUrlDecoder(), Base64.getMimeEncoder()/ Base64.getMimeDecoder()).

5.6. Tatasusunan Selari

Keluaran Java 8 menambah banyak kaedah baharu untuk pemprosesan tatasusunan selari. Mungkin yang paling penting ialah parallelSort(), yang boleh mempercepatkan pengisihan pada mesin berbilang teras. Contoh kecil di bawah menunjukkan kumpulan kaedah baharu ( parallelXxx) dalam tindakan.
package com.javacodegeeks.java8.parallel.arrays;

import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;

public class ParallelArrays {
    public static void main( String[] args ) {
        long[] arrayOfLong = new long [ 20000 ];

        Arrays.parallelSetAll( arrayOfLong,
            index -> ThreadLocalRandom.current().nextInt( 1000000 ) );
        Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
            i -> System.out.print( i + " " ) );
        System.out.println();

        Arrays.parallelSort( arrayOfLong );
        Arrays.stream( arrayOfLong ).limit( 10 ).forEach(
            i -> System.out.print( i + " " ) );
        System.out.println();
    }
}
Sekeping kod kecil ini menggunakan kaedah parallelSetAll()untuk mengisi tatasusunan dengan 20,000 nilai rawak. Selepas ini ia digunakan parallelSort(). Program ini mencetak 10 elemen pertama sebelum dan selepas mengisih untuk menunjukkan bahawa tatasusunan sebenarnya diisih. Output program contoh mungkin kelihatan seperti ini (Perhatikan bahawa elemen tatasusunan adalah rawak).
Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378
Sorted: 39 220 263 268 325 607 655 678 723 793

5.7. Paralelisme

Kaedah baharu telah ditambahkan pada kelas java.util.concurrent.ConcurrentHashMapuntuk menyokong operasi agregat berdasarkan objek strim dan ungkapan lambda yang baru ditambah. Kaedah baharu juga telah ditambahkan pada kelas java.util.concurrent.ForkJoinPooluntuk menyokong pengumpulan bersama (lihat juga kursus percuma kami tentang Java concurrency ). Kelas baharu java.util.concurrent.locks.StampedLocktelah ditambah untuk menyediakan penguncian berasaskan keupayaan dengan tiga mod akses untuk kawalan baca/tulis (ia boleh dianggap sebagai alternatif yang lebih baik kepada mod yang tidak begitu baik java.util.concurrent.locks.ReadWriteLock). Kelas baharu yang telah ditambahkan pada pakej java.util.concurrent.atomic:
  • DoubleAccumulator
  • DoubleAdder
  • LongAccumulator
  • LongAdder

6. Ciri baharu dalam persekitaran masa jalan Java (JVM)

Kawasan itu PermGentelah bersara dan digantikan oleh Metaspace (JEP 122). Pilihan JVM -XX:PermSizedan -XX:MaxPermSizetelah digantikan oleh -XX:MetaSpaceSizedan -XX:MaxMetaspaceSizemasing-masing.

7. Kesimpulan

Masa depan di sini: Java 8 telah menggerakkan platformnya ke hadapan dengan menyampaikan ciri yang membolehkan pembangun menjadi lebih produktif. Masih terlalu awal untuk memindahkan sistem pengeluaran ke Java 8, tetapi penerimaan harus perlahan-lahan mula berkembang dalam beberapa bulan akan datang. Walau bagaimanapun, kini adalah masa untuk mula menyediakan asas kod anda untuk keserasian Java 8 dan bersedia untuk memasukkan perubahan Java 8 apabila ia selamat dan cukup stabil. Sebagai bukti penerimaan masyarakat terhadap Java 8, Pivotal baru-baru ini mengeluarkan Rangka Kerja Spring dengan sokongan pengeluaran untuk Java 8 . Anda boleh memberikan input anda tentang ciri baharu yang menarik dalam Java 8 dalam ulasan.

8. Sumber

Beberapa sumber tambahan yang membincangkan pelbagai aspek ciri Java 8 secara mendalam:
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION