Fitur Baru di Java 8

1. Ikhtisar

Pada artikel ini, kita akan melihat sekilas beberapa fitur baru yang paling menarik di Java 8.

Kita akan berbicara tentang: default antarmuka dan metode statis, referensi metode dan Opsional.

Kami telah membahas beberapa fitur dari rilis Java 8 - API aliran, ekspresi lambda, dan antarmuka fungsional - karena keduanya adalah topik komprehensif yang pantas untuk dilihat secara terpisah.

2. Default Antarmuka dan Metode Statis

Sebelum Java 8, antarmuka hanya dapat memiliki metode abstrak publik. Tidak mungkin menambahkan fungsionalitas baru ke antarmuka yang ada tanpa memaksa semua kelas yang mengimplementasikan untuk membuat implementasi metode baru, juga tidak mungkin untuk membuat metode antarmuka dengan implementasi.

Dimulai dengan Java 8, antarmuka dapat memiliki metode statis dan default yang, meskipun dideklarasikan dalam antarmuka, memiliki perilaku yang ditentukan.

2.1. Metode Statis

Pertimbangkan metode antarmuka berikut (sebut saja Kendaraan antarmuka ini ):

static String producer() { return "N&F Vehicles"; }

Metode produser () statis hanya tersedia melalui dan di dalam antarmuka. Itu tidak bisa diganti oleh kelas pelaksana.

Untuk memanggilnya di luar antarmuka, pendekatan standar untuk panggilan metode statis harus digunakan:

String producer = Vehicle.producer();

2.2. Metode Default

Metode default dideklarasikan menggunakan kata kunci default baru . Ini dapat diakses melalui instance kelas pelaksana dan dapat diganti.

Mari tambahkan metode default ke antarmuka Kendaraan kami , yang juga akan membuat panggilan ke metode statis antarmuka ini:

default String getOverview() { return "ATV made by " + producer(); }

Asumsikan bahwa antarmuka ini diimplementasikan oleh kelas VehicleImpl. Untuk menjalankan metode default, instance dari kelas ini harus dibuat:

Vehicle vehicle = new VehicleImpl(); String overview = vehicle.getOverview();

3. Referensi Metode

Referensi metode bisa digunakan sebagai alternatif yang lebih pendek dan lebih mudah dibaca untuk ekspresi lambda yang hanya memanggil metode yang ada. Ada empat varian referensi metode.

3.1. Referensi ke Metode Statis

Referensi ke metode statis memegang sintaks berikut: ContainingClass :: methodName.

Mari kita coba menghitung semua string kosong dalam Daftar dengan bantuan Stream API.

boolean isReal = list.stream().anyMatch(u -> User.isRealUser(u));

Perhatikan ekspresi lambda lebih dekat dalam metode anyMatch () , itu hanya membuat panggilan ke metode statis isRealUser (User user) dari kelas User . Jadi bisa diganti dengan referensi ke metode statis:

boolean isReal = list.stream().anyMatch(User::isRealUser);

Jenis kode ini terlihat jauh lebih informatif.

3.2. Referensi ke Metode Instance

Referensi ke metode instance memegang sintaks berikut: c ontainingInstance :: methodName. Berikut kode panggilan metode isLegalName (String string) tipe User yang memvalidasi parameter input:

User user = new User(); boolean isLegalName = list.stream().anyMatch(user::isLegalName); 

3.3. Referensi ke Metode Instance dari Objek dari Jenis Tertentu

Metode referensi ini menggunakan sintaks berikut: C ontainingType :: methodName. Sebuah contoh::

long count = list.stream().filter(String::isEmpty).count();

3.4. Referensi ke Pembuat

Referensi ke konstruktor menggunakan sintaks berikut: ClassName :: new. Karena konstruktor di Java adalah metode khusus, referensi metode juga dapat diterapkan dengan bantuan new sebagai nama metode .

Stream stream = list.stream().map(User::new);

4. Opsional

Sebelum pengembang Java 8 harus dengan hati-hati memvalidasi nilai yang mereka rujuk, karena kemungkinan melempar NullPointerException (NPE) . Semua pemeriksaan ini menuntut kode boilerplate yang cukup mengganggu dan rawan kesalahan.

Java 8 Kelas opsional dapat membantu menangani situasi di mana ada kemungkinan mendapatkan NPE . Ia bekerja sebagai wadah untuk objek tipe T. Ia dapat mengembalikan nilai objek ini jika nilai ini bukan null . Jika nilai di dalam penampung ini adalah null, tindakan ini memungkinkan dilakukannya beberapa tindakan yang telah ditentukan sebelumnya daripada membuang NPE.

4.1. Penciptaan Opsional

Sebuah instance dari kelas Opsional dapat dibuat dengan bantuan metode statisnya:

Optional optional = Optional.empty();

Mengembalikan Opsional kosong .

String str = "value"; Optional optional = Optional.of(str);

Mengembalikan Opsional yang berisi nilai bukan nol.

Optional optional = Optional.ofNullable(getString());

Will return an Optional with a specific value or an empty Optional if the parameter is null.

4.2. Optional Usage

For example, you expect to get a List and in the case of null you want to substitute it with a new instance of an ArrayList. With pre-Java 8's code you need to do something like this:

List list = getList(); List listOpt = list != null ? list : new ArrayList();

With Java 8 the same functionality can be achieved with a much shorter code:

List listOpt = getList().orElseGet(() -> new ArrayList());

There is even more boilerplate code when you need to reach some object's field in the old way. Assume you have an object of type User which has a field of type Address with a field street of type String. And for some reason you need to return a value of the street field if some exist or a default value if street is null:

User user = getUser(); if (user != null) { Address address = user.getAddress(); if (address != null) { String street = address.getStreet(); if (street != null) { return street; } } } return "not specified";

This can be simplified with Optional:

Optional user = Optional.ofNullable(getUser()); String result = user .map(User::getAddress) .map(Address::getStreet) .orElse("not specified");

In this example we used the map() method to convert results of calling the getAdress() to the Optional and getStreet() to Optional. If any of these methods returned null the map() method would return an empty Optional.

Imagine that our getters return Optional. So, we should use the flatMap() method instead of the map():

Optional optionalUser = Optional.ofNullable(getOptionalUser()); String result = optionalUser .flatMap(OptionalUser::getAddress) .flatMap(OptionalAddress::getStreet) .orElse("not specified");

Another use case of Optional is changing NPE with another exception. So, as we did previously, let's try to do this in pre-Java 8's style:

String value = null; String result = ""; try { result = value.toUpperCase(); } catch (NullPointerException exception) { throw new CustomException(); }

And what if we use Optional? The answer is more readable and simpler:

String value = null; Optional valueOpt = Optional.ofNullable(value); String result = valueOpt.orElseThrow(CustomException::new).toUpperCase();

Notice, that how and for what purpose to use Optional in your app is a serious and controversial design decision, and explanation of its all pros and cons is out of the scope of this article. If you are interested, you can dig deeper, there are plenty of interesting articles on the Internet devoted to this problem. This one and this another one could be very helpful.

5. Conclusion

In this article, we are briefly discussing some interesting new features in Java 8.

There are of course many other additions and improvements which are spread across many Java 8 JDK packages and classes.

But, the information illustrated in this article is a good starting point for exploring and learning about some of these new features.

Akhirnya, semua kode sumber untuk artikel tersebut tersedia di GitHub.