Czy / dlaczego Java musi mieć void
metody? Odniesienie :
Żadna metoda zadeklarowana jako nieważna nie zwraca wartości.
O ile myślę, każde użycie void
byłoby lepiej obsługiwane przez zwrócenie flagi statusu, wywołanego obiektu lub null
.
To sprawiłoby, że każde wywołanie byłoby stwierdzeniem, które można przypisać, i ułatwiłoby budowanie wzorców i tworzenie łańcuchów metod. Metody wywoływane tylko dla ich efektów zwykle zwracają wartość logiczną lub Success
typ ogólny lub zgłaszają wyjątek w przypadku niepowodzenia.
java
programming-languages
return-type
marisbest2
źródło
źródło
Odpowiedzi:
Ponieważ istnieje różnica między „Ta funkcja może odnieść sukces lub zawieść i jest na tyle świadoma, że może odróżnić” i „Nie ma informacji zwrotnej na temat działania tej funkcji”. Bez
void
tego bez końca sprawdzasz kody sukcesu i wierzysz, że piszesz solidne oprogramowanie, podczas gdy w rzeczywistości nie robisz nic takiego.źródło
void
nie mówi nic o tym, czy metoda lub funkcja jest wystarczająco samoświadoma, aby rzucić odpowiednio.void
typ, a Java została zaprojektowana zgodnie z wieloma konwencjami rodziny języków C.Success
typem ogólnym ”? W rzeczywistości zwracane wartości wskazujące na sukces są nawet mniej ważne w Javie niż w C, ponieważ Java ma wyjątki wskazujące na niepowodzenie, a C nie.źródło
Void
Typ Java działa jako typ Jednostki (np. Dla Generics), choć niestety różni się odvoid
(uwaga: przytulanka umiera za każdym razem, gdy wymyślisz nowy typ, aby naprawić typ, który pomieszałeś w poprzedniej wersji). Jeśli ktoś nie jest zaznajomiony z typami jednostek, jest to przyzwoite wprowadzenie: en.wikipedia.org/wiki/Unit_typenull
(w rzeczywistości jest to jedyny wybór), ale null jest wyjątkową rzeczą, każda wartość typu odwołania w Javie może być null (jest to kolejny błąd w projektowaniu języka). I, jak powiedziałem wcześniej, jeśli używaszVoid
typu return zamiastvoid
znaku, kompilator Java nie jest twoim przyjacielem.null
. To, żenull
jest członkiem większości typów, nie ma znaczenia, czyVoid
jest to typ jednostki.Oryginalny powód, dla którego język ma
void
typ jest bo jak wC
, twórcy języka nie chce niepotrzebnie komplikować składnię języka z procedury s oraz funkcja ów drodze Pascal zrobił.To był pierwotny powód.
Twoje sugestie:
To nie-nie. Nie używamy flag stanu. Jeśli coś pójdzie nie tak, zgłaszamy to w drodze wyjątków.
Płynny styl wywoływania jest najnowszym osiągnięciem. Wielu programistów, którzy dzisiaj bardzo chętnie posługują się biegle i przewracają oczami, jeśli kiedykolwiek będą musieli użyć interfejsu, który go nie obsługuje, nie powstało nawet podczas tworzenia Java.
Zmusiłoby cię to do zadeklarowania metody jako zwracania czegoś, podczas gdy w rzeczywistości nic nie zwraca, więc byłoby to bardzo mylące dla kogoś, kto patrzy na interfejs próbujący dowiedzieć się, co on robi. Ludzie nieuchronnie wymyśliliby jakąś bezużyteczną klasę oznaczającą „brak wartości zwracanej”, aby wszystkie funkcje, które nie mają nic do zwrócenia, mogły zwrócić zerowe odwołanie do takiej klasy. To byłoby niezgrabne. Na szczęście istnieje na to rozwiązanie, nazywa się to
void
. I to jest odpowiedź na twoje pytanie.źródło
int
tak kluczowe dodano następnie do K i R „nie wskazuje typ zwrotny”.Niektóre metody, takie jak
System.out.println
, nie zwracają niczego użytecznego, ale są nazywane wyłącznie dla tego efektu ubocznego.void
jest pomocnym wskaźnikiem dla kompilatora i czytnika kodu, że żadna użyteczna wartość nie jest zwracana.Zwrot
null
zamiastvoid
oznacza, że po prostuNullPointerException
użyjesz tej wartości do czegokolwiek. Wymieniasz więc błąd czasu kompilacji na błąd czasu wykonywania, który jest znacznie gorszy. Ponadto należy zdefiniować typ zwrotu jakoObject
, co byłoby mylące i mylące. (A łańcuchowanie nadal nie działałoby.)Kody stanu są zwykle używane do wskazania warunków błędu, ale Java ma wyjątki w tym celu.
Zwrot
this
nie jest możliwy z metod statycznych.Zwrócenie ogólnego
Success
obiektu nie miałoby pożytecznego celu.źródło
Jednym z powodów jest to, że zwrócenie czegoś innego niż, powiedzmy, może być mylące
null
. Przykład:Co powinieneś
Arrays.sort(a)
zwrócić?Jeśli argumentujesz, że
a
należy zwrócić, aby połączenie mogło zostać powiązane (co wydaje się być twoją odpowiedzią na podstawie twojego pytania), to nie jest już jasne, czy zwracana wartość jest kopią oryginalnego obiektu, czy też samego obiektu oryginalnego . Oba są możliwe. I tak, możesz umieścić to w dokumentacji, ale jest to na tyle dwuznaczne, że nie powinieneś tworzyć dwuznaczności.Z drugiej strony, jeśli argumentujesz, że
null
powinien zostać zwrócony, nasuwa się pytanie o to, jakie informacje potencjalnie zwraca wartość zwracająca i dlaczego programista powinien być zmuszony do pisania,return null
gdy nie przekazuje żadnych informacji.A jeśli coś innego całkowicie absurdalne (jak długość powrócić
a
) to właśnie sprawia, że za pomocą tej wartości zwracanej naprawdę skomplikowane - wystarczy pomyśleć o ileż bardziej skomplikowane to znaczyint len = Arrays.sort(a)
zamiastint len = A.length
!źródło
return null;
- JVM mógłby równie dobrze nakazać, aby w przypadku, gdy kontrola wypadnie z końca funkcji w sposób inny niż jawnyreturn
lubthrow
instrukcja,null
pośrednio zwracana była do programu wywołującego. IIRC C robi to, z tą różnicą, że wartość zwracana jest niezdefiniowana w tym przypadku (będzie to dowolna wartość, która stanie się w miejscu używanym w tym czasie dla wartości zwracanej).return
instrukcji. Zamiast tego pojawia się błąd kompilatora informujący o pomyłce. Wprowadzenie niejawnegoreturn null;
byłoby lepsze niż „niezdefiniowane zachowanie”, ale niewiele. Przydałoby się to tylko wtedy, gdy typ zwracany nie ma znaczenia, ale skąd kompilator wyciąga wniosek, że wartość zwracana nie ma znaczenia, gdy nie jestvoid
?return
naprawdę nie dodaje żadnej wartości…”, cóż, jak już powiedziano, nie ma żadnego wskaźnika dla kompilatora, że zwrot nie dodałby żadnej wartości, jeśli nie ma żadnegovoid
typu. W rzeczywistości jest odwrotnie, pierwsze założenie jest takie, że metoda deklarująca typ zwracany chcereturn
czegoś użytecznego tego typu. I nie rozmawialiśmy jeszcze o typach pierwotnych, które nie mająnull
wartości, dlatego każda wartość domyślna wprowadzona przez kompilator byłaby w konflikcie z zakresem potencjalnie użytecznych wartości zwracanych.Zwracanie wartości,
boolean
która jest zawsze równa,true
którą sugerujesz, jest nie tylko bezcelowe (wartość zwracana nie zawiera żadnych informacji), ale w rzeczywistości byłaby myląca. Przez większość czasu, to najlepiej używać typów powrotne, które wykonują tylko tyle informacji, ile jest faktycznie dostępny - dlatego w Javie maszboolean
natrue
/false
zamiast Zwracanieint
z 4 miliardów możliwych wartości. Podobnie zwrócenie aboolean
z dwiema możliwymi wartościami, w przypadku których istnieje tylko jedna możliwa wartość („ogólny sukces”), byłoby mylące.Zwiększyłoby to również niepotrzebny narzut wydajności.
Jeśli metoda jest używana tylko ze względu na efekt uboczny, nie ma nic do zwrócenia, a typ zwrotu
void
dokładnie to odzwierciedla. Potencjalne rzadkie błędy mogą być sygnalizowane za pomocą wyjątków.Jedną rzeczą, którą można ulepszyć, byłoby stworzenie
void
rzeczywistego typu, takiego jak ScalaUnit
. Rozwiązałoby to niektóre problemy, takie jak obsługa leków generycznych.źródło
List.add
zawsze wracatrue
, ale to za zgodność z szerszą umowąCollection.add
, więcSet.add
może wrócićtrue
lubfalse
.Java jest stosunkowo starym językiem. A w 1995 r. (Kiedy został utworzony), a wkrótce potem programiści byli bardzo zaniepokojeni ilością czasu, jaką proces przejął kontrolę nad procesorem, a także zużyciem pamięci. Zwrócenie void wyeliminowałoby kilka cykli zegara i trochę zużycia pamięci z wywołania funkcji, ponieważ nie musiałbyś umieszczać wartości zwracanej na stosie, a następnie nie musiałbyś jej usuwać.
Efektywny kod nie daje ci czegoś, czego nigdy nie używałbyś, a zatem unieważnienie czegoś, co ma bezwartościową wartość zwrotną, jest znacznie lepszą praktyką niż zwracanie wartości sukcesu.
źródło
Przeczytałem argumenty sugerujące, że drugą opcją (return
this
) powinno być podejście zamiastvoid
. Jest to całkiem dobry pomysł, ale podejście w stylu konstruktora nie było popularne w czasie tworzenia Java. Gdyby w tym czasie był tak popularny, jak teraz, mogłoby to być przyjęte podejście. Powrótnull
to naprawdę zły pomysł IMO. Chciałbym, żebynull
w ogóle nie było tego języka.Problem polega na tym, że jeśli metoda zwraca instancję własnego typu, nie jest jasne, czy jest to nowy obiekt, czy ten sam. Często nie ma (lub nie powinien) mieć znaczenia, ale innym razem ma to znaczenie. Podejrzewam, że język mógłby zostać zmieniony, aby domyślnie powrócić
this
do nieważnych metod. Jedyną kwestią, o której mogę teraz pomyśleć, jest to, że jeśli później metoda zostanie zmieniona w celu zwrócenia nowego obiektu tego samego typu, nie pojawią się żadne ostrzeżenia dotyczące kompilacji, ale może to nie jest wielka sprawa. Obecny system typów nie przejmuje się teraz tego rodzaju zmianami. Sposób interakcji z dziedziczeniem / interfejsami wymagałby pewnych rozważań, ale pozwoliłby na łatwe wywoływanie starych interfejsów API bez stylu konstruktora, tak jakby to zrobiły.źródło
null
nie były częścią języka, ludzie używaliby wszelkiego rodzaju wartości wartowników, co oznacza „proszę zignoruj tę argument / wartość zwracaną, nie zawiera ona żadnej sensownej wartości”. Problememnull
nie jest sama rzecz, tylko to, że często jest używane nieprawidłowo. Założę się, że ten problem byłby przesadzony tylko wtedy, gdyby znormalizowanynull
zostałby zastąpiony niezliczonymi niestandardowymi rozwiązaniami, w których każda implementacja zachowywałaby się inaczej jak cicho ignorując użycie lub rzucając specjalne wyjątki zamiast standardowego wyjątku wskaźnika zerowego itp.null
jest właściwy typ opcjonalny (jakMaybe
w Haskell). Problem z zerami w Javie polega na tym, że nie ma rozsądnego sposobu, aby od razu zdecydować, czy wartość może być zerowana w praktyce, czy nie. Prowadzi to zarówno do: niepotrzebnie defensywnego programowania (sprawdzanie wartości zerowych tam, gdzie jest to bezcelowe, zwiększając procent kupy w kodzie), jak i przypadkowych NPE w produkcji (jeśli zapomniałem sprawdzić, gdzie było potrzebne). Tak, jest częściowo rozwiązany za pomocą adnotacji, ale są one opcjonalne, nie zawsze sprawdzane itp. Więc nie będą cię oszczędzać na granicach z kodem strony trzeciej.null
działa dobrze w tym przypadku (dobrze = prosto), ale znormalizowane wartości opcjonalne z solidną semantyką są zdecydowanie kolejną dobrą opcją (dobrze = bezpiecznie).Kolejny aspekt:
Java to język statyczny z dość ścisłymi funkcjami. Oznacza to, że wiele rzeczy, które byłyby dość otwarte lub dynamiczne w innych językach (c / f Ruby, Lisp itp.) Są ściśle określone.
Jest to ogólna decyzja projektowa. Na „dlaczego” trudno jest odpowiedzieć (cóż, ponieważ projektanci języka sądzili, że będzie dobrze!). „Po co” jest dość jasne: pozwala kompilatorowi wykryć wiele błędów, co ogólnie jest całkiem dobrą cechą dla każdego języka. Po drugie, sprawia, że stosunkowo łatwo jest zrozumieć język. Na przykład stosunkowo łatwo jest stworzyć formalne dowody poprawności w (podzestawach) języka Java; dla porównania byłoby to praktycznie niemożliwe w dynamicznym języku, takim jak Ruby i in.
Takie myślenie przenika język, na przykład wymuszoną deklarację możliwych wyjątków, które może rzucić metoda, osobny typ
interface
kontra,class
aby uniknąć niejednoznacznego wielokrotnego dziedziczenia i tak dalej. W rzeczywistości (statyczny imperialny język OOP w świecie rzeczywistym z silnym naciskiem na obsługę błędów w czasie kompilacji) te rzeczy są naprawdę dość eleganckie i potężne. Zbliżają się do języków teoretycznych (naukowych), które zostały celowo stworzone wyłącznie po to, aby zbadać niektóre z tych zagadnień niż jakikolwiek inny język rzeczywisty wcześniej (w tym czasie, pamiętajcie).Więc. Posiadanie ścisłego
void
typu jest wyraźnym komunikatem: ta metoda niczego nie zwraca, kropka. Jest jak jest. Zastąpienie go wymuszeniem, aby zawsze zwracało coś, prowadziłoby do znacznie bardziej dynamicznego zachowania (tak jak w Ruby, gdzie każdy def ma zawsze wyraźną lub dorozumianą wartość zwrotu), co byłoby niekorzystne z punktu widzenia sprawdzalności i uzasadnienia; lub do masywnego wzdęcia za pomocą innego mechanizmu tutaj.(I na przykład, Ruby (na przykład) radzi sobie z tym inaczej, a jego rozwiązanie jest nadal tak samo akceptowalne jak Java, ponieważ ma zupełnie inną filozofię. Na przykład wyrzuca możliwości sprawdzania się i rozsądności całkowicie poza okno, kładąc duży nacisk na wyjątkowo wysoka ekspresja języka).
źródło