Jenis Kekosongan di Jawa

1. Gambaran keseluruhan

Sebagai pengembang Java, kita mungkin pernah menemui jenis Void pada suatu ketika dan bertanya-tanya apa tujuannya.

Dalam tutorial ringkas ini, kita akan belajar mengenai kelas pelik ini dan melihat kapan dan bagaimana menggunakannya serta cara mengelak dari menggunakannya ketika mungkin.

2. Apakah Jenis Yang Tidak Sah

Sejak JDK 1.1, Java menyediakan kami jenis Void . Tujuannya hanyalah untuk menunjukkan jenis pengembalian yang tidak sah sebagai kelas dan mengandungi nilai awam Kelas . Ia tidak dapat dilakukan kerana satu-satunya pembangunnya adalah peribadi.

Oleh itu, satu-satunya nilai yang dapat kita berikan kepada pemboleh ubah Void adalah nol . Ia mungkin kelihatan tidak berguna, tetapi sekarang kita akan melihat kapan dan bagaimana menggunakan jenis ini.

3. Penggunaan

Terdapat beberapa situasi ketika menggunakan jenis Void boleh menarik.

3.1. Refleksi

Pertama, kita boleh menggunakannya semasa melakukan refleksi. Sesungguhnya, jenis pengembalian mana-mana kaedah kekosongan akan sepadan dengan pemboleh ubah Void.TYPE yang memegang nilai Kelas yang disebutkan sebelumnya .

Mari bayangkan kelas Kalkulator mudah :

public class Calculator { private int result = 0; public int add(int number) { return result += number; } public int sub(int number) { return result -= number; } public void clear() { result = 0; } public void print() { System.out.println(result); } }

Beberapa kaedah mengembalikan bilangan bulat, ada yang tidak mengembalikan apa-apa. Sekarang, katakan kita harus mengambil, melalui refleksi, semua kaedah yang tidak menghasilkan hasil . Kami akan mencapainya dengan menggunakan pembolehubah Void.TYPE :

@Test void givenCalculator_whenGettingVoidMethodsByReflection_thenOnlyClearAndPrint() { Method[] calculatorMethods = Calculator.class.getDeclaredMethods(); List calculatorVoidMethods = Arrays.stream(calculatorMethods) .filter(method -> method.getReturnType().equals(Void.TYPE)) .collect(Collectors.toList()); assertThat(calculatorVoidMethods) .allMatch(method -> Arrays.asList("clear", "print").contains(method.getName())); }

Seperti yang dapat kita lihat, hanya kaedah jelas () dan cetak () yang diambil.

3.2. Generik

Penggunaan lain dari jenis Void adalah dengan kelas generik. Katakan kita memanggil kaedah yang memerlukan parameter Callable :

public class Defer { public static  V defer(Callable callable) throws Exception { return callable.call(); } }

Tetapi, Callable yang ingin kita lalui tidak perlu mengembalikan apa-apa. Oleh itu, kita boleh lulus Callable :

@Test void givenVoidCallable_whenDiffer_thenReturnNull() throws Exception { Callable callable = new Callable() { @Override public Void call() { System.out.println("Hello!"); return null; } }; assertThat(Defer.defer(callable)).isNull(); }

Kita boleh menggunakan jenis rawak (misalnya Callable ) dan mengembalikan null atau tanpa jenis sama sekali ( Callable) , tetapi menggunakan Void menyatakan niat kita dengan jelas.

Kita juga boleh menggunakan kaedah ini untuk lambdas. Sebenarnya, Callable kami boleh ditulis sebagai lambda. Mari kita bayangkan kaedah yang memerlukan Fungsi , tetapi kita mahu menggunakan Fungsi yang tidak mengembalikan apa-apa. Maka kita mesti membuatnya mengembalikan Void :

public static  R defer(Function function, T arg) { return function.apply(arg); }
@Test void givenVoidFunction_whenDiffer_thenReturnNull() { Function function = s -> { System.out.println("Hello " + s + "!"); return null; }; assertThat(Defer.defer(function, "World")).isNull(); }

4. Bagaimana Mengelakkannya?

Sekarang, kami telah melihat beberapa penggunaan jenis Void . Walau bagaimanapun, walaupun penggunaan pertama benar-benar baik, kami mungkin ingin mengelakkan penggunaan Void dalam generik jika mungkin . Sesungguhnya, menghadapi jenis pengembalian yang mewakili ketiadaan hasil dan hanya boleh mengandungi nol boleh membebankan.

Kita sekarang akan melihat bagaimana untuk mengelakkan keadaan ini. Pertama, mari kita pertimbangkan kaedah kami dengan parameter Callable . Untuk mengelakkan penggunaan Callable , kami mungkin menawarkan kaedah lain dengan mengambil parameter Runnable sebagai gantinya:

public static void defer(Runnable runnable) { runnable.run(); }

Oleh itu, kita boleh memberikannya Runnable yang tidak mengembalikan nilai dan dengan itu menyingkirkan null return yang tidak berguna :

Runnable runnable = new Runnable() { @Override public void run() { System.out.println("Hello!"); } }; Defer.defer(runnable);

Tetapi kemudian, bagaimana jika kelas Defer bukan milik kita untuk diubah suai? Kemudian kita boleh berpegang pada pilihan Callable atau membuat kelas lain dengan mengambil Runnable dan menangguhkan panggilan ke kelas Defer :

public class MyOwnDefer { public static void defer(Runnable runnable) throws Exception { Defer.defer(new Callable() { @Override public Void call() { runnable.run(); return null; } }); } }

Dengan melakukan itu, kita merangkumi bahagian yang tidak praktikal sekali dan selamanya dalam kaedah kita sendiri, yang membolehkan pembangun masa depan menggunakan API yang lebih mudah.

Sudah tentu, perkara yang sama dapat dicapai untuk Fungsi . Dalam contoh kami, Fungsi tidak mengembalikan apa-apa, oleh itu kami dapat memberikan kaedah lain dengan mengambil Pelanggan sebagai gantinya:

public static  void defer(Consumer consumer, T arg) { consumer.accept(arg); }

Lalu, bagaimana jika fungsi kita tidak mengambil parameter apa pun? Kita boleh menggunakan Runnable atau membuat antara muka fungsional kita sendiri (jika nampak lebih jelas):

public interface Action { void execute(); }

Kemudian, kami membebankan lagi kaedah defer () :

public static void defer(Action action) { action.execute(); }
Action action = () -> System.out.println("Hello!"); Defer.defer(action);

5. Kesimpulan

Dalam artikel pendek ini, kami membahas kelas Java Void . Kami melihat apa tujuannya dan bagaimana menggunakannya. Kami juga mempelajari beberapa alternatif penggunaannya.

Seperti biasa, kod lengkap artikel ini boleh didapati di GitHub kami.