Java neden “boşluk” yöntemine sahip?


51

Java'nın neden / voidyöntem kullanması gerekiyor mu? Referans :

Geçersiz olarak bildirilen herhangi bir yöntem bir değer döndürmez.

Düşünebildiğim kadarıyla, her kullanımın voidbir durum bayrağı, çağrılan nesne veya null.

Bu, her çağrıyı atanabilir bir ifade haline getirir ve oluşturucu kalıplarını ve yöntem zincirlemesini kolaylaştırır. Yalnızca etkileri için çağrılan yöntemler genellikle bir boole veya genel Successtür döndürür veya başarısızlığa istisna atar.


Böylece alt yordamları yazmak için özel bir sözdizimine ihtiyacımız yoktur. Aynı işlevi kullanabiliriz.
candied_orange

Yanıtlar:


158

Çünkü "Bu işlev başarılı olabilir veya başarısız olabilir ve farkı anlayabilecek kadar farkındadır" ve "Bu işlevin etkisi hakkında geri bildirim yoktur" arasında bir fark vardır. Olmazsa void, başarı kodlarını hiç durmadan kontrol eder ve aslında hiçbir şey yapmıyorken sağlam bir yazılım yazdığınızı düşünürsünüz.


10
Ancak başarılı veya başarısız olup olmadığını, bir istisna fırlatıp atmayarak, bayrak göndermeyerek ifade etmek bir şeydir. Ve geri dönmek void, yöntemin veya işlevin uygun şekilde atmak için yeterince bilinçli olup olmadığı hakkında hiçbir şey söylemez.
Volker Siegel

12
@ VolkerSiegel: Cevabın içeriği soru. OP, boşluğun kullanıldığı tüm durumlarda, işlevin yerine başarısızlığın başarısını gösteren bir durum bayrağı getirmesi gerektiğini önerdi. Bu bağlamda boşluğun geri dönüşü DOES gerçekten de, işlevin tam anlamıyla döndürecek bir şeyi olmadığını söylüyor. Böyle bir işlevi başarıyı belirtmek için her zaman 0 döndürmeye zorlamak, kullanıcılara işlevi, gerçekte başarı veya başarısızlığa bakılmaksızın, gerçekte her zaman 0 olduğunda hata denetimi konusunda yanlış olduklarından emin olmalarını sağlar.
slebetman

19
@VolkerSiegel İstisnaların işleri yapmanın doğru yolu olmadığı çok sayıda durum vardır. Aslında, bir istisnanın yanlış olmaktan ötürü nadir olduğunu söyleyebilirim; istisna, dikkate alınması gereken korkunç bir şey olduğu anlamına gelir. Beklenen bir başarısızlık durumu asla bir istisna kullanmamalıdır.
Gabe Sechan

35
@GabeSechan Hayır, yöntem sözleşmeyi yerine getiremezse istisnalar da yapılmalıdır. Yöntem boş olmayan bir referans gerektiriyorsa ancak bir tane alıyorsa, bu beklenen bir hatadır ve atmalıdır.
Andy

5
Bunu düzeltmek için birçok alternatif sözdizimi vardır. Bu (garip) çözümü seçmelerinin nedeni C'nin kullanmasıdır.
Marco van de Voort

95
  1. Çünkü C'nin bir voidtürü vardır ve Java, C dili ailesinin birçok sözleşmesini izleyecek şekilde tasarlanmıştır.
  2. Bir değer döndürmek istemediğiniz birçok işlev vardır. SuccessZaten " jenerik tip" ile ne yapacaksın ? Aslında, başarıyı belirtmek için dönüş değerleri, Java'da C'den daha az önemlidir, çünkü Java'nın başarısızlığı belirtmek için istisnaları vardır ve C değildir.

8
> "Genel bir başarı türü" neyse "ne yapacaksın?" - Genel kod yazarken, tek bir değer tipi (btw olarak adlandırılır) çok kullanışlıdır, çünkü “sadece dönen” ancak özel bir şey getirmeyen özel fonksiyon durumlarını ortadan kaldırır. Fakat Java ilk yaratıldığında, daha az etkileyici bir yazım sistemine sahipti (yazım parametresi olmadan), bu yüzden çok fazla pratik bir fark yoktu. Ve şimdi değişmek için çok geç. Daha modern diller aslında "type" (aslında bir tür değil, yalnızca yöntemler için özel bir işaretleyicidir) geçersiz kılmakta ve bunun yerine Unit türünü kullanmaktadır.
Sarge Borsch

9
@SargeBorsch Java'nın Voidtürü, Birim türü olarak işlev görür (örneğin, Jenerikler için), ne yazık ki, farklıdır void(yan not: sevimli bir yavru kedi, önceki sürümde karıştırdığınız yazıyı düzeltmek için her yeni bir tür bulduğunuzda ölür). Birim türlerine aşina olmayan biri varsa, bu iyi bir giriş: en.wikipedia.org/wiki/Unit_type
Ogre Psalm33

1
@ OgrePsalm33 gerçekten bir Birim türü olarak hareket etmiyor (en azından pratikte - bir tanesi hala "return" yazmalı; Void return türüne sahip bir yöntemden dönmek için AFAIK derleyicisi Void referansları için yığında yer ayırıyor. (bu değerleri hiç okumanın anlamsız olduğu gerçeğinden yararlanmamak), "uygun" Birim türünün daha uygun olacağı yerlerde kullanmak sadece bir kuraldır.
Sarge Borsch

3
@ immibis çünkü tanım olarak Birim türünün tam olarak bir değeri olması ve Void'in değerleri olmaması gerekir. Evet, kullanmak mümkündür null(aslında tek seçenek budur), ancak null özel bir şeydir, Java'daki referans türünün değeri boş olabilir (bu, dil tasarımındaki başka bir hatadır). Daha önce de söylediğim gibi, işaret Voidyerine return türünü kullanıyorsanız void, Java derleyicisi arkadaşınız değildir.
Sarge Borsch

5
@SargeBorsch Void, tam olarak bir değere sahiptir null. Aslında nullçoğu türde bir üyesi olup olmadığını alakasız Voidbir birim tipidir.
user253751

65

Orijinal dili vardır sebebi voidgibi çünkü türünü ise C, dilin yaratıcıları gereksiz yere sahip dilin sözdizimi zorlaştırmak istemedim prosedür s ve fonksiyon Pascal yaptılar lar şekilde.

Asıl sebep buydu.

Önerileriniz:

durum bayrağı döndürme

Bu bir hayır-hayır. Durum bayrakları kullanmıyoruz. Eğer bir şeyler ters giderse, istisnalar yoluyla rapor ederiz.

çağrılan nesne

Akıcı çağrı tarzı son zamanlardaki bir gelişmedir. Bugün çok mutlu bir şekilde akıcı kullanan ve hiç desteklemeyen bir arayüz kullanmak zorunda kalırlarsa, Java oluşturulduğunda bile doğmamış olan programcıların çoğu gözlerini yuvarlar.

boş değer döndürüyor

Bu, bir yöntemi bir şeyi geri döndürme olarak ilan etmeye zorlar, aslında bir şeyi geri getirmediğinde, onun ne olduğunu anlamaya çalışan bir arayüze bakan biri için çok kafa karıştırıcı olurdu. İnsanlar kaçınılmaz olarak “geri dönüş değeri olmayan” anlamına gelen bazı işe yaramaz bir sınıf icat ederlerdi, böylece geri döndürecek bir şeyi olmayan tüm fonksiyonlar böyle bir sınıfa null bir referans verebilir. Bu clunky olurdu. Neyse ki, buna bir çözüm var, denir void. Ve bu sorunuzun cevabı.


3
Lütfen "Özgün sebep ..." için bir kaynak girin. Bildiğim kadarıyla asıl sebep, C'nin taşınabilir bir montajcı olarak tasarlanmasıydı.
Thorbjørn Ravn Andersen

6
@ ThorbjørnRavnAndersen, gerçekten, aslında, java'nın sözdiziminin C sözdiziminden kaynaklandığı iddiası için bir kaynak sağlamamı mı istiyorsunuz?
Mike Nakis

3
@ ThorbjørnRavnAndersen oh, anladım, yanlış anladım. Öyleyse C ile ilgili iddiam için bir kaynak istiyorsun, Java ile ilgili değil. Tamam, üzgünüm, bunun için bir kaynağım yok. Ama bence oldukça açık. (Eskiden 1987’de C’ye geçtiğimde Pascal’da programlandım. Aman Allah’ım, bu 30 yıl önceydi.)
Mike Nakis

6
Bu belli değil. C kabaca aynı zamanda pascal ile aynı zamanda geliştiğini bile bilmiyordu. Lütfen varsayımları gerçek olarak belirtmeyin.
Thorbjørn Ravn Andersen

12
Gerçek orijinal nedeni varsayılan C fonksiyonları döndü tarafından olmasıydı int, bu yüzden bir anahtar kelime 'hayır dönüş türü' belirtmek için K & R takiben eklenmiştir.
user207421

20

Bazı yöntemler, gibi System.out.printlnfaydalı bir şey getirmez, ancak bu yan etki için tamamen denir. voidderleyici ve kod okuyucusu için yararlı bir değer döndürülmeyen yararlı bir göstergedir.

nullBunun yerine geri dönmek void, sadece NullPointerExceptionbu değeri herhangi bir şey için kullandığınız anı elde edersiniz. Böylece çalışma zamanı hatası için derleme zamanı hatası ile işlem yapabilirsiniz. Ayrıca, dönüş türünü Objectyanıltıcı ve kafa karıştırıcı olacak şekilde tanımlamanız gerekir. (Ve zincirleme hala işe yaramaz.)

Durum kodları genellikle hata durumlarını belirtmek için kullanılır, ancak Java'nın bu amaç için istisnaları vardır.

thisStatik yöntemlerle geri dönüş mümkün değildir.

Genel bir Successnesneyi döndürmenin hiçbir faydası olmaz.


1
En basit ve özlü cevap olarak sizinle tamamen aynı fikirdeyim.
webo80

11

Bunun bir nedeni , diyelim ki başka hiçbir şeyden geri dönmenin yanıltıcı olabilmesidir null. Örnek:

Ne Arrays.sort(a)dönmeli?

aÇağrının zincirlenebilmesi için geri gönderilmesi gerektiğini savunuyorsanız (bu, sorunuzu değerlendiren cevabınız gibi görünüyor), o zaman geri dönüş değerinin orijinal nesnenin bir kopyası mı yoksa orijinal nesnenin kendisinin mi olduğu artık net değil . Her ikisi de mümkün. Ve evet, onu belgelere koyabilirsiniz, ama belirsizliği ilk başta oluşturmamanız yeterince yeterince belirsizdir.

Öte yandan, eğer nullgeri dönmesi gerektiğini savunuyorsanız , bu, geri dönüş değerinin arayan kişiye hangi bilgileri sağladığı ve programcının neden return nullhiçbir bilgi aktarmadığı zaman yazmaya zorlanması gerektiği sorusuna cevap verir.

Eğer tamamen saçma (uzunluğu gibi başka bir şeyi dönerseniz Ve a) o zaman sadece gerçekten kafa karıştırıcı olduğunu dönüş değeri kullanarak yapar - sadece bunu söylemek ne kadar daha kafa karıştırıcı düşünüyorum int len = Arrays.sort(a)yerine int len = A.length!


1
Bütün adaletlerde, programcının mutlaka yazması gerekmeyecektir return null;- JVM, kontrolün bir fonksiyonun sonunu açık returnveya throwifadeden başka bir yolla düştüğü takdirde nullarayanın kendisine iade edilmesini zorunlu kılabilir. IIRC C, bu durumda, dönüş değerinin tanımsız olması dışında (o zaman, dönüş değeri için kullanılan konumda ne olursa olsun olacak olanı olacaktır) yapar.
17'de CVn

2
Kalın sorunuzu doğru cevap "sıralı bir dizi" dir.
Bryan Boettcher

2
@BryanBoettcher: Kalanını okumadın mı?
Mehrdad

1
@Michael Kjörling: Bu tür hataları önlemek, yani bir returnifadeyi unutursanız “tanımsız davranış” yapmamak, Java dilinin temel bir özelliğidir . Bunun yerine, size hatanız hakkında bir derleyici hatası veriyorsunuz. Örtük eklemek, return null;“tanımsız davranış” dan daha iyi olurdu, ama çok değil. Bu, sadece geri dönüş tipi bir anlam ifade etmediğinde faydalı olabilir, ancak derleyici, sonuç değerinin nereden çıktığı, geri dönüş değerinin bir anlamı olmadığı sonucuna varır voidmı?
Holger

2
@ MichaelKjörling: “Eğer returngerçekten herhangi bir değer katmazsa …”, dediği gibi, derleyici için herhangi bir tür olmadığında bir getirinin herhangi bir değer katmayacağına dair bir gösterge yoktur void. Aslında bunun tam tersi, ilk varsayım, bir geri dönüş türü bildiren bir yöntemin returnbu türden yararlı bir şey istediğidir . Ve henüz ilkel tiplerden bahsetmedik, bir nulldeğeri yok, dolayısıyla derleyici tarafından enjekte edilen herhangi bir varsayılan değer, potansiyel olarak yararlı geri dönüş değerleri aralığıyla çelişir.
Holger

7

booleanHer zaman trueönerdiğinize eşit olanı döndürmek , yalnızca anlamsız değildir (dönüş değeri hiçbir bilgi içermez), ama aslında yanıltıcı olur. Çoğu zaman, sadece gerçekten mümkün olduğu kadar fazla bilgi taşıyan iade türlerini kullanmak en iyisidir - bu yüzden Java'da 4 milyar olası değere sahip olmaktansa / sahip booleanolduğunuz true/ almanızın nedeni budur . Benzer şekilde, yalnızca bir olası değerin ("genel başarı") olduğu iki olası değere sahip bir değer döndürmek yanıltıcı olacaktır.falseintboolean

Ayrıca gereksiz performans ek yükü de eklerdi.

Bir yöntem yalnızca yan etkisi için kullanılırsa, geri döndürülecek bir şey yoktur ve geri dönüş türü voidtam olarak bunu yansıtır. Muhtemel nadir hatalar istisnalar aracılığıyla bildirilebilir.

İyileştirilebilecek bir şey, voidScala'nınki gibi gerçek bir tür yapmaktı Unit. Bu, jenerik ilaçlarla çalışmak gibi bazı sorunları çözecektir.


Eğlenceli gerçek: List.addher zaman geri döner true, ancak bunun daha geniş bir sözleşmeyle uyumlu olması için Collection.add, yani Set.addgeri dönebilir trueveya false.
Holger

4

Java nispeten eski bir dildir. Ve 1995'te (Yaratıldığı zaman) ve bundan kısa bir süre sonra programcılar bir işlemin işlemciyi kontrol altına almasının yanı sıra bellek tüketimini de çok fazla endişelendiriyordu. Boşluğa geri dönmek, bir işlev çağrısından birkaç saat döngüsünü ve bir miktar bellek tüketimini ortadan kaldırır çünkü dönüş değerini yığına koymak zorunda kalmazsınız ve daha sonra bunları çıkarmak zorunda kalmazsınız.

Verimli kod size asla kullanmayacağınız bir şeyi geri vermez ve bu nedenle anlamsız bir geri dönüş değeri olan bir şeyi geçersiz kılmak, bir başarı değeri döndürmekten çok daha iyi bir uygulamadır.


14
Hız konusunda çok endişeli olan programcılar, bugünlerde Java kullanmayacaktı, çünkü ilk Java uygulamaları oldukça yavaştı. O kadar yavaş ki, şu anda çalışmayan birçok insan hala Java’nın yağ ile eşanlamlı olduğu izlenimi altında.
Sarge Borsch

8
@SargeBorsch bana 20 yıl önceki eski bir programlama şakasını hatırlatıyor. "Vur, Vur" "Oradaki kim?" ... ... ... ... çok uzun bir duraklama ... ... ... "Java"
Dan Neely,

4
@DanNeely ve bir süre sonra, AI ile çalışan bir araba, duvarları tam hızda çarpıyor, hatta fren kullanmaya çalışmıyor. Java ile yazılmış. Yani, Java şimdi fren yapmıyor! (Rus dilinde çok başarılıydı, İngilizce'yi çok iyi
çeviremiyor

2
@SargeBorsch Çeviride nüansını kaybetmiş olsa bile İngilizce bir punto olarak çalışıyorsunuz. Tercüme edici püf noktaları çevirmek muhtemelen şiirden daha zordur.
Dan Neely,

3
İyi programcılar hala performans ve bellek tüketimi ile ilgilenmektedir, bu da gereksiz yere insanlardan bugün bile ilgili çöpleri geri almalarını istemektedir.
Sklivvz

2

İkinci seçeneğin (return this) bunun yerine yaklaşım olması gerektiğini öne süren argümanları okudum void. Bu oldukça iyi bir fikir ama üretici tarzı yaklaşım Java'nın yaratıldığı tarihte popüler değildi. O zamanlar şu anda olduğu kadar popüler olsaydı, bu, yaklaşılan yaklaşım olabilirdi. nullIMO, geri dönmek gerçekten kötü bir fikir. Keşke nulldilde bile olmasaydı.

Şimdi sorun şu ki, eğer bir yöntem kendi türünün bir örneğini verirse, bunun yeni bir nesne mi yoksa aynı mı olduğu belli değildir. Genellikle önemli değil (ya da olmamalı) ama önemli olduğu başka zamanlarda. Sanırım, dil thisgeçersiz kılma yöntemiyle örtük olarak geri dönecek şekilde değiştirilebilirdi . Şu an bununla ilgili düşünebildiğim tek sorun, eğer yöntem daha sonra aynı türden yeni bir nesneyi döndürmek için değiştirilirse, derleme uyarısı olmayacaktı ama bu belki de önemli bir şey değil. Şu anki tip sistem bu tip değişiklikleri şimdi umursamıyor. Bunun kalıtım / arayüzler ile nasıl etkileşime gireceği biraz düşünülmeye ihtiyaç duyar, ancak eski stil API'leri yapıcı bir stili olmayan kolayca sanki sanki çağrılır.


2
@Cody İyi nokta, bu statik yöntemlere uygulanmaz.
JimmyJames

14
@ marisbest2 Hangi tartışma?
8,

3
Eğer nulldilin bir parçası olmasaydı, insanlar “lütfen bu argümanı / dönüş değerini dikkate almayın, mantıklı bir değer içermiyor” anlamına gelen her türlü sentinel değerlerini kullanırlardı. Sorun, sorunun nullkendisi değil, yalnızca yanlış kullanılması eğilimindedir. Bu sorunun sadece standart hale getirilmiş nullolması durumunda, her uygulamanın sessizce kullanımı görmezden gelmek veya standart bir boş gösterici istisnası yerine özel istisnalar atmak gibi farklı davranışlar sergileyeceği sayısız özel çözümle değiştirilirse abartılacağına bahse girerim .
cmaster

2
@cmaster için bariz bir değiştirme işlemi nulluygun bir isteğe bağlı türdür ( MaybeHaskell'de olduğu gibi ). Java'daki boş değerlerle ilgili sorun, pratikte bir değerin geçersiz olup olmadığına hemen karar vermenin akıllıca bir yolu olmamasıdır. Bu, her ikisine de yol açar: Gereksiz yere savunma programlaması (anlamsız olduğu yerlerde null değerlerini kontrol etme, böylece koddaki poop yüzdesini artırma) ve üretimde yanlışlıkla NPE'leri (gerektiğinde kontrol etmeyi unuttuysa). Evet, kısmen ek açıklamalarla çözülür, ancak isteğe bağlıdır, her zaman kontrol edilmez, vb. Böylece sizi üçüncü taraf kodu ile sınırlardan kurtarmazlar.
Sarge Borsch

2
@SargeBorsch Buna katılıyorum :-) İtirazım, "lütfen bu değeri dikkate almayın" ifadesini standart bir şekilde kullanmayan bir dile karşı. nullBunun için iyi çalışıyor (iyi = basit), ancak katı anlambilim ile standartlaştırılmış isteğe bağlı değerler kesinlikle başka bir iyi seçenek (iyi = güvenli).
cmaster

2

Başka bir yönü:

Java, oldukça katı özelliklere sahip statik bir dildir. Bu, diğer dillerde (c / f Ruby, Lisp vb.) Oldukça açık veya dinamik olacak birçok şeyin kesin olarak belirlendiği anlamına gelir.

Bu genel bir tasarım kararıdır. “Neden” diye cevaplamak zor (çünkü dilin tasarımcıları bunun iyi olacağını düşündü!). "Ne için" oldukça açık: derleyicinin bir çok hatayı tespit etmesini sağlar , bu genellikle herhangi bir dil için oldukça iyi bir özelliktir. İkincisi, dil hakkında akıl yürütmeyi nispeten kolay hale getirir. Örneğin, biçimsel doğruluk oluşturmak Java dilinde (altkümelerinde) kanıtlamak nispeten kolaydır; Karşılaştırma olarak, Ruby ve diğerleri gibi dinamik bir dilde neredeyse imkansız olurdu.

Bu düşünce, dilin, örneğin, bir yöntemin ortaya koyabileceği olası istisnaların zorla ilan edilmesine, belirsiz çoklu mirastan kaçınmanın ayrı türüne interfacevs. classizin verir. Ne olduğu için (derleme zamanı hata işlemeye kuvvetli odaklanan statik bir zorunlu OOP gerçek dünya dili) bu şeyler aslında oldukça zarif ve güçlü. Sadece bu konuların bazılarını araştırmak için daha önce herhangi bir gerçek dünya diline nazaran keşfedilmeyi amaçlayan teorik (bilime uygun) dillere daha da yaklaşıyorlar (o zaman, sizi düşünün).

Yani. Sıkı bir voidtüre sahip olmak açık bir mesajdır: bu yöntem hiçbir şey döndürmez, dönem. Neyse ne. Bir şeyi her zaman geri döndürmek için onu zorlamak yerine, daha fazla dinamik davranışa yol açabilir (Ruby'de her def'in açık ya da örtülü bir geri dönüş değeri olduğu yerlerde olduğu gibi ), her zaman provability ve muhakeme için kötü olurdu; veya burada başka bir mekanizma kullanarak büyük şişkinlik.

(Ve NB, Yakut (örneğin) farklı bu işler ve bunun çözüm hala tam olarak kabul edilebilir , Java'nın olarak tamamen farklı bir felsefeye sahiptir çünkü koyarken. Mesela o pencereden dışarı tamamen sağlamasının ve mantıklılığını atar geniş odak üzerinde dilin son derece yüksek ifadesi.)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.