JavaRush /Java Blog /Random-ID /Fitur Java 8 – Panduan Utama (Bagian 2)
0xFF
Level 9
Донецк

Fitur Java 8 – Panduan Utama (Bagian 2)

Dipublikasikan di grup Random-ID
Bagian kedua dari terjemahan artikel Fitur Java 8 – Panduan ULTIMATE . Bagian pertama ada di sini (link dapat berubah). Fitur Java 8 – Panduan Utama (Bagian 2) - 1

5. Fitur baru di perpustakaan Java 8

Java 8 telah menambahkan banyak kelas baru dan memperluas kelas yang sudah ada untuk lebih mendukung konkurensi modern, pemrograman fungsional, tanggal/waktu, dan banyak lagi.

5.1. Kelas Opsional

NullPointerException yang terkenal sejauh ini merupakan penyebab paling umum kegagalan aplikasi Java. Dahulu kala, proyek luar biasa Google, Guava, disajikan Optionalsebagai solusi NullPointerException, sehingga mencegah kode tercemar oleh pemeriksaan nol, dan sebagai hasilnya mendorong penulisan kode yang lebih bersih. Kelas Guava yang terinspirasi Google Optionalkini menjadi bagian dari Java 8. OptionalKelas ini hanyalah sebuah wadah: dapat berisi nilai atau beberapa tipe Т, atau hanya berupa null. Ini menyediakan banyak metode yang berguna sehingga pemeriksaan null eksplisit tidak lagi dibenarkan. Lihat dokumentasi resmi untuk informasi lebih rinci. 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!" ) );
Metode isPresent()mengembalikan nilai benar jika instance Optionalberisi nilai bukan nol dan salah jika sebaliknya. Metode ini orElseGet()berisi mekanisme fallback untuk hasil jika Optionalberisi null, menerima fungsi untuk menghasilkan nilai default. Metode map () mengubah nilai saat ini Optionaldan mengembalikan instance baru Optional. Metodenya orElse()mirip dengan orElseGet(), tetapi alih-alih menggunakan fungsi, metode ini menggunakan nilai default. Berikut adalah output dari program ini:
Full Name is set? false
Full Name: [none]
Hey Stranger!
Mari kita lihat contoh lainnya:
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 seperti ini:
First Name is set? true
First Name: Tom
Hey Tom!
Untuk informasi lebih detail, silakan merujuk ke dokumentasi resmi .

5.2. Aliran

Stream API ( ) yang baru ditambahkanjava.util.stream memperkenalkan gaya pemrograman fungsional nyata di Java. Sejauh ini, ini merupakan tambahan terlengkap pada pustaka Java dan memungkinkan pengembang Java menjadi jauh lebih efisien dan juga memungkinkan mereka membuat kode yang efisien, bersih, dan ringkas. Stream API membuat pemrosesan koleksi menjadi lebih mudah (tetapi tidak terbatas pada koleksi tersebut, seperti yang akan kita lihat nanti). Mari kita ambil kelas sederhana 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 memiliki beberapa poin (atau kesulitan semu) dan dapat berupa OPEN atau CLOSE . Mari kita perkenalkan kumpulan 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 )
);
Pertanyaan pertama yang ingin kami ketahui adalah berapa banyak poin yang terdapat dalam tugas OPEN saat ini? Sebelum Java 8, solusi yang biasa dilakukan adalah menggunakan iterator foreach. Namun di Java 8, jawabannya adalah stream: rangkaian elemen yang mendukung operasi agregat berurutan dan paralel.
// Подсчет общего количества очков всех активных задач с использованием sum()
final long totalPointsOfOpenTasks = tasks
    .stream()
    .filter( task -> task.getStatus() == Status.OPEN )
    .mapToInt( Task::getPoints )
    .sum();

System.out.println( "Total points: " + totalPointsOfOpenTasks );
Dan keluaran konsol akan terlihat seperti:
Total points: 18
Mari kita lihat apa yang terjadi di sini. Pertama, kumpulan tugas diubah menjadi representasi streaming. Operasi kemudian filtermenyaring semua tugas dengan status DITUTUP . Pada langkah berikutnya, operasi mapToIntmengubah stream Tasks menjadi stream Integers menggunakan metode Task::getPointsuntuk setiap instance Task. Terakhir, semua poin dijumlahkan menggunakan metode ini sum, yang memberikan hasil akhir. Sebelum melanjutkan ke contoh berikutnya, ada beberapa catatan tentang thread yang perlu diingat (detail lebih lanjut di sini ). Operasi streamdibagi menjadi operasi perantara dan operasi akhir . Operasi perantara mengembalikan aliran baru. Mereka selalu malas; ketika melakukan operasi perantara seperti filter, mereka tidak benar-benar melakukan pemfilteran, melainkan membuat aliran baru, yang bila selesai, berisi elemen aliran asli yang sesuai dengan predikat yang diberikan. Operasi terbatas , seperti forEachdan sum, dapat dilewatkan melalui aliran untuk menghasilkan hasil atau efek samping. Setelah operasi terakhir selesai, aliran dianggap telah digunakan dan tidak dapat digunakan lagi. Di hampir semua kasus, operasi akhir cenderung menyelesaikan traversalnya melalui sumber data yang mendasarinya. Fitur berharga lainnya dari thread adalah dukungan untuk proses paralel yang siap pakai. Mari kita lihat contoh ini, yang menemukan jumlah skor semua soal.
// 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 mirip dengan contoh pertama, hanya saja kami mencoba memproses semua tugas secara paralel dan menghitung hasil akhirnya menggunakan metode ini reduce. Inilah keluaran konsolnya:
Total points (all tasks): 26.0
Seringkali ada kebutuhan untuk mengelompokkan elemen menurut kriteria tertentu. Contoh ini menunjukkan bagaimana thread dapat membantu dalam hal ini.
// Группировка задач по их статусу
final Map<Status, List<Task>> map = tasks
    .stream()
    .collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );
Output konsolnya adalah sebagai berikut:
{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}
Untuk menyelesaikan contoh soal, mari kita hitung persentase keseluruhan (atau bobot) setiap soal dalam kumpulan berdasarkan total poin:
// Подсчет веса каждой задачи (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 konsolnya akan seperti ini:
[19%, 50%, 30%]
Terakhir, seperti yang kami catat sebelumnya, Stream API tidak hanya untuk koleksi Java. Operasi I/O yang khas, seperti membaca file teks baris demi baris, adalah kandidat yang sangat baik untuk menggunakan pemrosesan aliran. 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 );
}
Metode ini onConsole, yang dipanggil pada sebuah thread, mengembalikan thread yang setara dengan penangan pribadi tambahan. Penangan pribadi dipanggil ketika suatu metode close()dipanggil pada thread. Stream API bersama dengan lambda dan metode referensi serta metode default dan statis di Java 8 adalah jawaban terhadap paradigma pengembangan perangkat lunak modern. Untuk informasi lebih detail, silakan merujuk ke dokumentasi resmi .

5.3. API Tanggal/Waktu (JSR 310)

Java 8 menghadirkan tampilan baru pada manajemen tanggal dan waktu dengan menyediakan API Tanggal dan Waktu baru (JSR 310) . Manipulasi tanggal dan waktu adalah salah satu masalah terburuk bagi pengembang Java. Standar java.util.Dateberikut ini java.util.Calendarumumnya tidak memperbaiki situasi (bahkan mungkin membuatnya lebih membingungkan). Begitulah lahirnya Joda-Time : alternatif API tanggal/waktu yang bagus untuk Java . API Tanggal/Waktu baru di Java 8 (JSR 310) sangat dipengaruhi oleh Joda-Time dan mengambil yang terbaik darinya. Paket baru java.timeberisi semua kelas untuk tanggal, waktu, tanggal/waktu, zona waktu, durasi, dan manipulasi waktu . Desain API memperhatikan kekekalan dengan sangat serius: perubahan tidak diperbolehkan (pelajaran sulit yang didapat dari java.util.Calendar). Jika modifikasi diperlukan, instance baru dari kelas terkait akan dikembalikan. Mari kita lihat kelas utama dan contoh penggunaannya. Kelas pertama Clock, yang menyediakan akses ke instan, tanggal dan waktu saat ini menggunakan zona waktu. Clockdapat digunakan sebagai pengganti System.currentTimeMillis()dan TimeZone.getDefault().
// Получить системное время How смещение UTC
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );
Contoh keluaran konsol:
2014-04-12T15:19:29.282Z
1397315969360
Kelas baru lainnya yang akan kita lihat adalah LocaleDatedan LocalTime. LocaleDatehanya berisi bagian tanggal tanpa zona waktu dalam sistem kalender ISO-8601. Oleh karena itu, LocalTimeini hanya berisi sebagian dari kode waktu>.
// получить местную 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 keluaran konsol:
2014-04-12
2014-04-12
11:25:54.568
15:25:54.568
LocalDateTimemenggabungkan LocaleDatedan LocalTimedan berisi tanggal dan waktu, tetapi tidak ada zona waktu, dalam sistem kalender ISO-8601. Contoh sederhana diberikan di bawah ini.
// 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 keluaran konsol:
2014-04-12T11:37:52.309
2014-04-12T15:37:52.309
Jika Anda memerlukan tanggal/waktu untuk zona waktu tertentu, ZonedDateTime. Ini berisi tanggal dan waktu dalam sistem kalender ISO-8601. Berikut adalah beberapa contoh untuk zona waktu yang berbeda.
// Получение даты/времени для временной зоны
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 keluaran 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 terakhir, mari kita lihat kelasnya Duration: rentang waktu dalam hitungan detik dan nanodetik. Hal ini membuat perhitungan antara dua tanggal menjadi sangat sederhana. Mari kita lihat cara melakukannya:
// Получаем разницу между двумя датами
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 menghitung durasi (dalam hari dan jam) antara dua tanggal, 16 April 2014 dan 16 April 2015 . Berikut adalah contoh keluaran konsol:
Duration in days: 365
Duration in hours: 8783
Kesan keseluruhan tanggal/waktu baru di Java 8 sangat-sangat positif. Sebagian karena perubahan tersebut didasarkan pada fondasi yang telah teruji dalam pertempuran (Joda-Time), sebagian lagi karena kali ini masalah tersebut dipertimbangkan kembali secara serius dan suara para pengembang didengarkan. Untuk detailnya, silakan merujuk ke dokumentasi resmi .

5.4. Mesin JavaScript Nashorn

Java 8 hadir dengan mesin JavaScript Nashorn baru , yang memungkinkan Anda mengembangkan dan menjalankan jenis aplikasi JavaScript tertentu di JVM. Mesin JavaScript Nashorn hanyalah implementasi lain dari javax.script.ScriptEngine yang mengikuti serangkaian aturan yang sama untuk memungkinkan Java dan JavaScript berinteraksi. Berikut ini contoh kecilnya.
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 keluaran konsol:
jdk.nashorn.api.scripting.NashornScriptEngine
Result: 2

5.5. Basis64

Terakhir, dukungan untuk pengkodean Base64 masuk ke perpustakaan standar Java dengan dirilisnya Java 8. Sangat mudah digunakan, contoh menunjukkan hal 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 dari program ini menampilkan teks yang dikodekan dan didekode:
QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!
Ada juga kelas untuk encoder/decoder yang ramah URL, serta encoder/decoder yang ramah MIME ( Base64.getUrlEncoder()/ Base64.getUrlDecoder(), Base64.getMimeEncoder()/ Base64.getMimeDecoder()).

5.6. Array Paralel

Rilis Java 8 menambahkan banyak metode baru untuk pemrosesan array paralel. Mungkin yang paling penting adalah parallelSort(), yang dapat mempercepat penyortiran pada mesin multi-inti. parallelXxxContoh kecil di bawah ini menunjukkan cara kerja rangkaian metode baru ( ).
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();
    }
}
Sepotong kecil kode ini menggunakan metode parallelSetAll()untuk mengisi array dengan 20.000 nilai acak. Setelah ini diterapkan parallelSort(). Program ini mencetak 10 elemen pertama sebelum dan sesudah pengurutan untuk menunjukkan bahwa array benar-benar diurutkan. Contoh keluaran program mungkin terlihat seperti ini (Perhatikan bahwa elemen array bersifat acak).
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

Metode baru telah ditambahkan ke kelas java.util.concurrent.ConcurrentHashMapuntuk mendukung operasi agregat berdasarkan objek aliran dan ekspresi lambda yang baru ditambahkan. Metode baru juga telah ditambahkan ke kelas java.util.concurrent.ForkJoinPooluntuk mendukung pengumpulan bersama (lihat juga kursus gratis kami tentang konkurensi Java ). Kelas baru java.util.concurrent.locks.StampedLocktelah ditambahkan untuk menyediakan penguncian berbasis kemampuan dengan tiga mode akses untuk kontrol baca/tulis (ini dapat dianggap sebagai alternatif yang lebih baik daripada yang kurang bagus java.util.concurrent.locks.ReadWriteLock). Kelas baru yang telah ditambahkan ke paket java.util.concurrent.atomic:
  • Akumulator Ganda
  • Penambah Ganda
  • Akumulator Panjang
  • Penambah Panjang

6. Fitur baru di Java runtime environment (JVM)

Area tersebut PermGentelah dihentikan dan digantikan oleh Metaspace (JEP 122). Opsi JVM -XX:PermSizedan -XX:MaxPermSizetelah digantikan oleh -XX:MetaSpaceSizedan -XX:MaxMetaspaceSizemasing-masing.

7. Kesimpulan

Masa depan ada di sini: Java 8 telah memajukan platformnya dengan menghadirkan fitur-fitur yang memungkinkan pengembang menjadi lebih produktif. Masih terlalu dini untuk memindahkan sistem produksi ke Java 8, namun penerapannya akan mulai tumbuh secara perlahan dalam beberapa bulan ke depan. Namun, sekaranglah waktunya untuk mulai mempersiapkan basis kode Anda untuk kompatibilitas Java 8 dan bersiap untuk menerapkan perubahan Java 8 jika sudah cukup aman dan stabil. Sebagai bukti penerimaan komunitas terhadap Java 8, Pivotal baru-baru ini merilis Spring Framework dengan dukungan produksi untuk Java 8 . Anda dapat memberikan masukan Anda tentang fitur-fitur baru yang menarik di Java 8 di kolom komentar.

8. Sumber

Beberapa sumber tambahan yang membahas berbagai aspek fitur Java 8 secara mendalam:
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION