Mengapa Java memiliki metode `void`?

51

Apakah / mengapa Java perlu memiliki voidmetode? Referensi :

Metode apa pun yang dinyatakan batal tidak mengembalikan nilai.

Sejauh yang saya bisa pikirkan, setiap penggunaan voidakan lebih baik dilayani dengan mengembalikan bendera status, objek yang dipanggil, atau null.

Ini akan membuat setiap panggilan pernyataan yang ditugaskan, dan akan memfasilitasi pola pembangun dan metode chaining. Metode yang hanya digunakan untuk efeknya biasanya akan mengembalikan boolean atau Successtipe generik atau memberikan pengecualian pada kegagalan.

marisbest2
sumber
Sehingga kita tidak perlu sintaks khusus untuk menulis subrutin. Kita bisa menggunakan fungsi yang sama.
candied_orange
Relevan
jpmc26

Jawaban:

158

Karena ada perbedaan antara "Fungsi ini dapat berhasil atau gagal dan cukup sadar sehingga dapat membedakan" dan "Tidak ada umpan balik tentang efek fungsi ini." Tanpa void, Anda akan terus-menerus memeriksa kode sukses dan percaya bahwa Anda sedang menulis perangkat lunak yang kuat, padahal sebenarnya Anda tidak melakukan hal semacam itu.

Kilian Foth
sumber
10
Tetapi apakah itu berhasil atau gagal adalah sesuatu untuk diekspresikan dengan melempar atau tidak melempar pengecualian, tidak mengembalikan bendera. Dan kembali voidtidak mengatakan apa-apa tentang apakah metode atau fungsi cukup sadar untuk melempar yang sesuai.
Volker Siegel
12
@VolkerSiegel: Konteks dari jawabannya adalah pertanyaan. OP menyarankan bahwa dalam semua kasus di mana kekosongan digunakan fungsi seharusnya mengembalikan bendera status yang menunjukkan keberhasilan kegagalan. Dalam konteks yang mengembalikan batal, memang tidak mengatakan bahwa fungsi itu secara harfiah tidak ada jalan untuk kembali. Memaksa fungsi seperti itu untuk selalu mengembalikan 0 untuk menunjukkan keberhasilan akan memberi pengguna fungsi salah kepercayaan bahwa mereka memeriksa kesalahan ketika pada kenyataannya nilai kembali selalu 0 terlepas dari keberhasilan atau kegagalan.
slebetman
19
@VolkerSiegel Ada sejumlah besar situasi di mana pengecualian bukanlah cara yang tepat untuk melakukan sesuatu. Sebenarnya saya akan mengatakan bahwa pengecualian untuk benar atau salah jarang terjadi - pengecualian berarti sesuatu yang mengerikan terjadi yang perlu dipertanggungjawabkan. Kasus kegagalan yang diharapkan tidak boleh menggunakan pengecualian.
Gabe Sechan
35
@ GabeSechan Tidak, pengecualian harus dilemparkan jika metode ini tidak dapat memenuhi kontraknya. Jika metode ini membutuhkan referensi nonnull tetapi mendapatkannya, itulah kegagalan yang diharapkan dan harus dibuang.
Andy
5
Ada banyak sintaks alternatif untuk memperbaikinya. Alasan mereka memilih solusi (canggung) ini adalah karena C mempekerjakannya.
Marco van de Voort
95
  1. Karena C memiliki voidtipe, dan Java dirancang untuk mengikuti banyak konvensi dari keluarga bahasa C.
  2. Ada banyak fungsi yang Anda tidak ingin mengembalikan nilai. Apa yang akan Anda lakukan dengan " Successtipe generik "? Pada kenyataannya, nilai pengembalian untuk menunjukkan keberhasilan bahkan kurang penting di Jawa daripada di C, karena Jawa memiliki pengecualian untuk menunjukkan kegagalan dan C tidak.
Mason Wheeler
sumber
8
> "Lagi pula, apa yang akan Anda lakukan dengan" tipe Sukses generik "? - ketika menulis kode generik, tipe nilai tunggal (disebut tipe Unit btw) sangat berguna karena menghilangkan kasus khusus fungsi yang "hanya kembali" tetapi tidak mengembalikan apa pun secara khusus. Tetapi ketika Java pertama kali dibuat, ia bahkan memiliki sistem tipe yang kurang ekspresif (tanpa parameter tipe), sehingga tidak ada banyak perbedaan praktis. Dan sekarang sudah terlambat untuk berubah. Lebih banyak bahasa modern benar-benar menghindari "tipe" kekosongan (sebenarnya ini bahkan bukan tipe, hanya penanda khusus untuk metode) dan gunakan tipe Unit sebagai gantinya.
Sarge Borsch
9
@SargeBorsch tipe Java Voidbertindak sebagai tipe Unit (misalnya untuk Generik), meskipun sayangnya, ini berbeda dari void(catatan: kucing yang suka diemong mati setiap kali Anda menemukan tipe baru untuk memperbaiki tipe yang Anda buat di versi sebelumnya). Jika ada yang tidak terbiasa dengan tipe Unit, ini adalah pengantar yang layak: en.wikipedia.org/wiki/Unit_type
Ogre Psalm33
1
@ OgrePsalm33 ia tidak benar-benar bertindak sebagai tipe Unit (setidaknya dalam cara praktis - seseorang masih harus menulis "return null;" untuk kembali dari metode yang memiliki tipe return Void, dan kompiler AFAIK mengalokasikan ruang pada stack untuk referensi Void , tidak mengambil keuntungan dari fakta bahwa tidak ada gunanya untuk membaca nilai-nilai ini), itu hanyalah sebuah konvensi untuk menggunakannya di mana tipe Unit yang "tepat" akan lebih tepat.
Sarge Borsch
3
@immibis karena tipe Unit menurut definisi harus memiliki tepat satu nilai, dan Void tidak memiliki nilai. Ya, itu mungkin untuk digunakan null(sebenarnya ini adalah satu-satunya pilihan), tetapi null adalah hal yang istimewa, nilai jenis referensi apa pun di Jawa mungkin nol (ini adalah kesalahan lain dalam desain bahasa). Dan, seperti yang saya katakan sebelumnya, jika Anda menggunakan Voidtipe kembali bukan voidtanda, kompiler Java bukan teman Anda.
Sarge Borsch
5
@SargeBorsch Void memiliki tepat satu nilai, yaitu null. Fakta bahwa nullanggota adalah tipe yang paling tidak relevan dengan apakah Voidtipe unit.
user253751
65

The original alasan mengapa bahasa memiliki voidtipe ini karena seperti di C, pencipta bahasa tidak ingin tidak perlu mempersulit sintaks dari bahasa dengan prosedur dan fungsi s cara Pascal lakukan.

Itulah alasan aslinya.

Saran Anda:

mengembalikan bendera status

Itu tidak-tidak. Kami tidak menggunakan bendera status. Jika terjadi kesalahan, kami melaporkannya melalui pengecualian.

objek yang dipanggil

Gaya doa yang lancar adalah perkembangan baru-baru ini. Banyak programmer yang sangat senang menggunakan lancar hari ini dan memutar mata mereka jika mereka harus menggunakan antarmuka yang tidak mendukung itu bahkan tidak dilahirkan ketika Java dibuat.

mengembalikan nol

Itu akan memaksa Anda untuk mendeklarasikan metode sebagai mengembalikan sesuatu, padahal sebenarnya itu tidak mengembalikan apa pun, jadi itu akan sangat membingungkan bagi seseorang yang sedang melihat antarmuka yang mencoba mencari tahu apa fungsinya. Orang pasti akan menemukan beberapa kelas yang tidak berguna yang berarti "tidak ada nilai kembali" sehingga semua fungsi yang tidak memiliki apa pun untuk dikembalikan dapat mengembalikan referensi nol ke kelas seperti itu. Itu akan kikuk. Untungnya, ada solusi untuk ini, begitulah namanya void. Dan itulah jawaban untuk pertanyaan Anda.

Mike Nakis
sumber
3
Harap berikan sumber untuk "Alasan asli ...". Setahu saya alasan sebenarnya adalah karena C dirancang untuk menjadi assembler portabel.
Thorbjørn Ravn Andersen
6
@ ThorbjørnRavnAndersen apakah Anda benar-benar meminta saya untuk menyediakan sumber untuk klaim bahwa sintaks java berasal dari sintaks C?
Mike Nakis
3
@ ThorbjørnRavnAndersen oh, begitu, saya salah paham. Jadi, Anda ingin sumber untuk klaim saya tentang C, bukan tentang Java. Oke, maaf, saya tidak punya sumber untuk itu. Tapi saya pikir itu agak jelas. (Dulu saya memprogram di Pascal pada 1987, ketika saya beralih ke C. Ya ampun, itu 30 tahun yang lalu.)
Mike Nakis
6
Itu tidak jelas. C dikembangkan kira-kira bersamaan dengan pascal oleh orang-orang yang kemungkinan besar bahkan tidak tahu keberadaannya. Tolong jangan nyatakan asumsi sebagai fakta.
Thorbjørn Ravn Andersen
12
The nyata Alasan asli adalah bahwa secara default fungsi C kembali int, jadi kata kunci ditambahkan setelah K & R untuk menunjukkan 'tipe kembali'.
user207421
20

Beberapa metode, seperti System.out.printlntidak mengembalikan apa pun yang bermanfaat, tetapi disebut murni untuk efek samping ini. voidadalah indikator yang bermanfaat untuk kompiler dan bagi pembaca kode yang tidak mengembalikan nilai berguna.

Mengembalikan nullbukan voidberarti Anda hanya akan mendapatkan NullPointerExceptionmomen saat Anda menggunakan nilai ini untuk apa pun. Jadi Anda menukar kesalahan waktu kompilasi dengan kesalahan runtime yang jauh lebih buruk. Selain itu, Anda harus mendefinisikan tipe pengembalian sebagai Object, yang akan menyesatkan dan membingungkan. (Dan merantai masih tidak akan berhasil.)

Kode status biasanya digunakan untuk menunjukkan kondisi kesalahan, tetapi Java memiliki pengecualian untuk tujuan ini.

Pengembalian thistidak dimungkinkan dari metode statis.

Mengembalikan Successobjek generik tidak akan memiliki tujuan yang bermanfaat.

JacquesB
sumber
1
Sepenuhnya setuju dengan Anda, jawaban yang paling sederhana dan ringkas.
webo80
11

Salah satu alasannya adalah bahwa bisa menyesatkan untuk mengembalikan apa pun selain, katakanlah null,. Contoh:

Apa yang harus Arrays.sort(a)dikembalikan?

Jika Anda berargumen bahwa itu aharus dikembalikan sehingga panggilan itu dapat dirantai (yang nampaknya merupakan tanggapan Anda berdasarkan pertanyaan Anda), maka tidak lagi jelas apakah nilai pengembalian adalah salinan dari objek asli, atau objek asli itu sendiri . Keduanya mungkin. Dan ya, Anda bisa memasukkannya ke dalam dokumentasi, tetapi cukup ambigu bahwa Anda tidak boleh membuat ambiguitas sejak awal.

Di sisi lain, jika Anda berpendapat bahwa itu nullharus dikembalikan, itu menimbulkan pertanyaan tentang informasi apa yang mungkin diberikan oleh nilai balik si penelepon, dan mengapa programmer harus dipaksa untuk menulis return nullketika tidak ada informasi yang disampaikan.

Dan jika Anda mengembalikan sesuatu yang benar-benar absurd (seperti panjangnya a) maka itu hanya membuat menggunakan nilai pengembalian itu benar-benar membingungkan - pikirkan saja betapa jauh lebih membingungkannya int len = Arrays.sort(a)daripada mengatakan int len = A.length!

Mehrdad
sumber
1
Dalam semua keadilan, programmer tidak perlu diminta untuk menulis return null;- JVM bisa juga mengamanatkan bahwa jika kontrol jatuh dari akhir fungsi dengan cara lain selain eksplisit returnatau throwpernyataan, nullsecara implisit dikembalikan ke pemanggil. IIRC C melakukan itu, kecuali bahwa nilai kembali tidak ditentukan dalam kasus itu (itu akan menjadi nilai apa pun yang terjadi di lokasi yang digunakan untuk nilai kembali pada saat itu).
CVn
2
Jawaban yang benar untuk pertanyaan tebal Anda adalah, "array yang diurutkan".
Bryan Boettcher
2
@BryanBoettcher: Apakah Anda tidak membaca sisanya?
Mehrdad
1
@Michael Kjörling: ini adalah properti mendasar dari bahasa Java untuk mencegah kesalahan seperti itu, yaitu tidak memiliki "perilaku tidak terdefinisi" jika Anda lupa sebuah returnpernyataan. Sebagai gantinya, Anda mendapatkan kesalahan kompiler yang memberi tahu Anda tentang kesalahan Anda. Memasukkan implisit return null;akan lebih baik daripada "perilaku tidak terdefinisi", tetapi tidak banyak. Itu akan berguna hanya ketika tipe kembali tidak memiliki arti, tetapi di mana kompiler menarik kesimpulan dari, bahwa nilai kembali tidak memiliki makna, padahal bukan void?
Holger
2
@ MichaelKjörling: "Jika yang returnbenar - benar tidak menambah nilai apa pun ...", yah, seperti yang dikatakan, tidak ada indikator untuk kompiler bahwa pengembalian tidak akan menambah nilai apa pun, jika tidak ada voidjenis. Ini sebenarnya kebalikannya, asumsi pertama adalah bahwa metode yang menyatakan tipe pengembalian ingin returnsesuatu yang berguna dari jenis itu. Dan kami belum berbicara tentang tipe primitif, yang tidak memiliki nullnilai, karenanya, nilai default apa pun yang disuntikkan oleh kompiler akan bertentangan dengan kisaran nilai pengembalian yang berpotensi bermanfaat.
Holger
7

Mengembalikan booleanyang selalu sama dengan trueyang Anda sarankan, tidak hanya sia-sia (nilai pengembalian tidak membawa informasi), tetapi sebenarnya akan menyesatkan. Sebagian besar waktu, yang terbaik untuk menggunakan jenis kembali yang hanya membawa informasi sebanyak benar-benar tersedia - itu sebabnya di Jawa Anda memiliki booleanuntuk true/ falsedaripada kembali sebuah intdengan 4 miliar nilai yang mungkin. Demikian juga, mengembalikan a booleandengan dua nilai yang mungkin di mana hanya ada satu nilai yang mungkin ("kesuksesan generik"), akan menyesatkan.

Itu juga akan menambah overhead kinerja yang tidak perlu.

Jika suatu metode hanya digunakan untuk efek sampingnya, tidak ada yang kembali, dan tipe pengembalian voidmencerminkan hal itu. Potensi kesalahan langka dapat ditandai melalui pengecualian.

Satu hal yang bisa diperbaiki, adalah membuat voidtipe yang sebenarnya, seperti milik Scala Unit. Ini akan menyelesaikan beberapa masalah seperti penanganan obat generik.

Michał Kosmulski
sumber
Fakta menyenangkan: List.addselalu kembali true, tetapi itu karena kompatibel dengan kontrak yang lebih luas Collection.add, jadi Set.adddapat kembali trueatau false.
Holger
4

Java adalah bahasa yang relatif lama. Dan pada tahun 1995 (Ketika itu dibuat) dan tak lama kemudian programmer sangat peduli tentang jumlah waktu proses mengambil kendali prosesor serta konsumsi memori. Membatalkan kembali akan menghilangkan beberapa siklus jam dan sedikit konsumsi memori dari panggilan fungsi karena Anda tidak harus meletakkan nilai kembali pada tumpukan, dan Anda tidak perlu menghapusnya lagi.

Kode efisien tidak memberi Anda kembali sesuatu yang tidak akan pernah Anda gunakan, dan karenanya membatalkan sesuatu yang memiliki nilai pengembalian yang tidak berarti adalah praktik yang jauh lebih baik daripada mengembalikan nilai keberhasilan.

The Lazy Coder
sumber
14
programmer yang sangat peduli dengan kecepatan tidak akan menggunakan Java hari ini, karena implementasi pertama dari Java terkenal lambat. Begitu lambat sehingga banyak orang yang saat ini tidak bekerja dengannya masih di bawah kesan bahwa Jawa adalah sinonim untuk gemuk dan lambat.
Sarge Borsch
8
@SargeBorsch mengingatkan saya pada lelucon pemrograman lama dari 20 tahun yang lalu. "Ketuk, Ketuk." "Siapa disana?" ... ... ... ... jeda yang sangat lama ... ... ... "Java"
Dan Neely
4
@DanNeely dan beberapa saat kemudian, sebuah mobil yang digerakkan oleh AI menabrak dinding dengan kecepatan penuh, bahkan tidak mencoba menggunakan rem. Itu ditulis di Jawa. Jadi, Java tidak mengerem sekarang! (Itu adalah pelesetan dalam bahasa Rusia, tidak dapat menerjemahkannya ke bahasa Inggris dengan sangat baik)
Sarge Borsch
2
@SargeBorsch Apa yang Anda miliki berfungsi sebagai bahasa Inggris, meskipun itu kehilangan nuansa terjemahan. Dan menerjemahkan permainan kata-kata mungkin lebih sulit daripada puisi.
Dan Neely
3
Pemrogram yang baik masih memperhatikan kinerja dan konsumsi memori, yang membuat orang tidak perlu mengembalikan sampah yang relevan bahkan hingga hari ini.
Sklivvz
2

Saya sudah membaca argumen yang menyarankan bahwa opsi kedua (kembali this) harus menjadi pendekatan alih-alih void. Ini adalah ide yang cukup bagus tetapi pendekatan gaya pembangun tidak populer pada saat Java dibuat. Jika itu sama populernya pada saat itu seperti sekarang, itu mungkin pendekatan yang diambil. Kembali nulladalah ide IMO yang sangat buruk. Saya berharap nullbahkan tidak dalam bahasa sama sekali.

Masalahnya sekarang adalah bahwa jika suatu metode mengembalikan turunan dari tipe miliknya sendiri, tidak jelas apakah itu objek baru atau objek yang sama. Seringkali itu tidak (atau tidak seharusnya) penting tetapi di lain waktu itu penting. Saya kira bahasanya bisa diubah untuk secara implisit mengembalikan thismetode yang kosong. Satu-satunya masalah yang dapat saya pikirkan dengan itu saat ini adalah bahwa jika metode ini kemudian diubah untuk mengembalikan objek baru dari jenis yang sama, tidak akan ada peringatan kompilasi tetapi itu mungkin bukan masalah besar. Sistem tipe saat ini tidak peduli dengan jenis perubahan ini sekarang. Bagaimana ini berinteraksi dengan warisan / antarmuka akan memerlukan beberapa pertimbangan tetapi itu akan memungkinkan API lama tanpa gaya builder dengan mudah disebut seolah-olah mereka melakukannya.

JimmyJames
sumber
2
@Cody Poin bagus, ini tidak akan berlaku untuk metode statis.
JimmyJames
14
@ marisbest2 Argumen yang mana?
8bittree
3
Nah, jika nullbukan bagian dari bahasa, orang akan menggunakan segala macam nilai sentinel yang berarti "tolong abaikan nilai argumen / pengembalian ini, itu tidak mengandung nilai yang masuk akal". Masalah dengan nullbukanlah hal itu sendiri, hanya saja cenderung digunakan secara tidak benar. Saya berani bertaruh bahwa masalah ini hanya akan dilebih-lebihkan jika yang terstandarisasi nullakan diganti dengan segudang solusi khusus, di mana setiap implementasi akan berperilaku berbeda seperti diam-diam mengabaikan penggunaan, atau melemparkan pengecualian khusus alih-alih pengecualian penunjuk nol standar, dll.
cmaster
2
@ cmaster pengganti yang jelas untuk nulladalah tipe opsional yang tepat (seperti, Maybedi Haskell). Masalah dengan nulls di Java adalah bahwa tidak ada cara yang waras untuk segera memutuskan apakah suatu nilai nullable dalam praktik atau tidak. Ini mengarah pada keduanya: pemrograman defensif yang tidak perlu (memeriksa nol di mana tidak ada gunanya, sehingga meningkatkan persentase kotoran dalam kode), dan NPEs yang tidak disengaja dalam produksi (jika lupa memeriksa di mana diperlukan). Ya, sebagian diselesaikan oleh anotasi tetapi mereka opsional, tidak selalu diperiksa, dll. Sehingga mereka tidak akan menyelamatkan Anda pada batas dengan kode pihak ketiga.
Sarge Borsch
2
@SargeBorsch Saya setuju dengan itu :-) Keberatan saya bertentangan dengan bahasa tanpa cara standar untuk mengekspresikan "tolong abaikan nilai ini". nullberfungsi dengan baik untuk ini (fine = sederhana), tetapi nilai opsional terstandarisasi dengan semantik yang solid jelas merupakan opsi bagus lainnya (fine = safe).
cmaster
2

Aspek lain:

Java adalah bahasa statis dengan fitur yang cukup ketat. Ini berarti bahwa banyak hal yang cukup terbuka atau dinamis dalam bahasa lain (c / f Ruby, Lisp dll.) Sangat ditentukan.

Ini adalah keputusan desain umum. "Mengapa" sulit untuk dijawab (baik, karena perancang bahasa berpikir itu akan baik!). "Untuk apa" cukup jelas: memungkinkan kompiler mendeteksi banyak kesalahan, yang umumnya merupakan fitur yang cukup baik untuk bahasa apa pun. Kedua, itu membuatnya relatif mudah untuk berpikir tentang bahasa. Misalnya, relatif mudah untuk membuat pembenaran formal dalam (himpunan bagian) bahasa Jawa; sebagai perbandingan, itu akan menjadi hampir mustahil dalam bahasa yang dinamis seperti Ruby et al.

Pemikiran ini meresapi bahasa, misalnya, deklarasi paksa tentang kemungkinan pengecualian yang dapat dilemparkan oleh suatu metode, tipe interfacevs yang terpisah classuntuk menghindari pewarisan berganda yang ambigu, dan sebagainya. Untuk apa itu (OOP imperatif statis bahasa dunia nyata dengan fokus yang kuat pada penanganan kesalahan waktu kompilasi) hal-hal itu sebenarnya cukup elegan dan kuat. Mereka datang lebih dekat ke bahasa teoretis (sains) yang sengaja dibuat hanya untuk mengeksplorasi beberapa masalah ini daripada bahasa dunia nyata lainnya sebelumnya (pada waktu itu, ingatlah).

Begitu. Memiliki voidtipe yang ketat adalah pesan yang jelas: metode ini tidak mengembalikan apa pun, titik. Itu adalah apa adanya. Menggantinya dengan penegakan untuk selalu mengembalikan sesuatu akan mengarah pada perilaku yang jauh lebih dinamis (seperti di Ruby di mana setiap def memiliki nilai pengembalian yang eksplisit atau implisit, selalu), yang akan berdampak buruk bagi provabilitas dan alasan; atau untuk mengasapi dengan menggunakan mekanisme lain di sini.

(Dan NB, Ruby (misalnya) menangani hal ini secara berbeda, dan solusinya masih dapat diterima seperti halnya Java, karena ia memiliki filosofi yang sama sekali berbeda. Misalnya ia melempar provabilitas dan kewajaran sepenuhnya dari jendela sambil menempatkan fokus besar pada ekspresi bahasa yang sangat tinggi.)

AnoE
sumber