Jest to jedna z zasad, które powtarzają się w kółko i to mnie denerwuje.
Wartości zerowe są złe i należy ich unikać, gdy tylko jest to możliwe .
Ale, ale - z mojej naiwności pozwól mi krzyczeć - czasami wartość MOGĄ być wyraźnie nieobecna!
Pozwól, że zapytam o przykład, który pochodzi z tego okropnego kodu opartego na anty-wzorcach, nad którym obecnie pracuję . Jest to, w gruncie rzeczy, gra sieciowa dla wielu graczy, w której tury obu graczy są uruchamiane jednocześnie (jak w Pokemon i przeciwnie do szachów).
Po każdej kolejce serwer rozgłasza listę aktualizacji kodu JS po stronie klienta. Klasa aktualizacji:
public class GameUpdate
{
public Player player;
// other stuff
}
Ta klasa jest serializowana do JSON i wysyłana do podłączonych graczy.
Większość aktualizacji wiąże się oczywiście z graczem - w końcu trzeba wiedzieć, który gracz wykonał ruch w tej turze. Jednak niektóre aktualizacje nie mogą mieć z nimi istotnego powiązania. Przykład: Gra została remisowana siłą, ponieważ limit obrotów bez akcji został przekroczony. Wydaje mi się, że w przypadku takich aktualizacji zerowanie odtwarzacza ma sens.
Oczywiście mogę „naprawić” ten kod, wykorzystując dziedziczenie:
public class GameUpdate
{
// stuff
}
public class GamePlayerUpdate : GameUpdate
{
public Player player;
// other stuff
}
Jednak nie widzę, jak to się poprawia, z dwóch powodów:
- Kod JS będzie teraz po prostu odbierał obiekt bez Player jako zdefiniowaną właściwość, która jest taka sama, jakby była pusta, ponieważ oba przypadki wymagają sprawdzenia, czy wartość jest obecna, czy nie;
- Gdyby do klasy GameUpdate dodano kolejne pole zerowalne, musiałbym mieć możliwość wielokrotnego dziedziczenia, aby kontynuować to projektowanie - ale MI jest samo w sobie złe (według bardziej doświadczonych programistów) i, co ważniejsze, C # nie mam, więc nie mogę go użyć.
Mam wrażenie, że ten fragment tego kodu jest jednym z wielu, w których doświadczony, dobry programista krzyczałby z przerażeniem. Jednocześnie nie widzę, jak w tym miejscu nic nie rani niczego i co zamiast tego należy zrobić.
Czy możesz mi wyjaśnić ten problem?
źródło
Odpowiedzi:
Dużo rzeczy lepiej jest zwrócić niż zero.
(co sprawiło, że uznałeś, że jest ona pusta)
Sztuką jest uświadomienie sobie, kiedy to zrobić. Null jest naprawdę dobry w wysadzaniu w twarz, ale tylko wtedy, gdy go dotrzesz, nie sprawdzając go. Nie jest dobry w wyjaśnianiu, dlaczego.
Jeśli nie musisz wysadzać w powietrze i nie chcesz sprawdzać wartości zerowej, skorzystaj z jednej z tych alternatyw. Zwracanie kolekcji może wydawać się dziwne, jeśli zawiera ona zawsze 0 lub 1 elementów, ale jest naprawdę dobra w cichym radzeniu sobie z brakującymi wartościami.
Monady brzmią fantazyjnie, ale tutaj wszystko, co robią, pozwala ci dać do zrozumienia, że prawidłowe rozmiary kolekcji to 0 i 1. Jeśli masz, rozważ je.
Każdy z nich lepiej radzi sobie z wyjaśnianiem intencji niż zero. To najważniejsza różnica.
Może pomóc zrozumieć, dlaczego w ogóle wracasz, niż po prostu zgłaszasz wyjątek. Wyjątki są zasadniczo sposobem na odrzucenie założenia (nie są jedynym sposobem). Kiedy pytasz o punkt, w którym przecinają się dwie linie, zakładasz, że przecinają się. Mogą być równoległe. Czy należy wprowadzić wyjątek dotyczący „linii równoległych”? Cóż, możesz, ale teraz musisz poradzić sobie z tym wyjątkiem gdzie indziej lub pozwolić mu zatrzymać system.
Jeśli wolisz pozostać tam, gdzie jesteś, możesz przekształcić odrzucenie tego założenia w rodzaj wartości, która może wyrażać wyniki lub odrzucenia. To nie jest takie dziwne. Cały czas robimy to w algebrze . Sztuką jest nadanie tej wartości znaczenia, abyśmy mogli zrozumieć, co się stało.
Jeśli zwrócona wartość może wyrażać wyniki i odrzucenia, należy ją wysłać do kodu obsługującego oba te elementy. Polimorfizm jest tutaj naprawdę potężny. Zamiast po prostu wymieniać czeki zerowe na
isPresent()
czeki, możesz napisać kod, który zachowuje się dobrze w obu przypadkach. Albo zastępując puste wartości wartościami domyślnymi, albo dyskretnie nic nie robiąc.Problem z wartością null polega na tym, że może to oznaczać zbyt wiele rzeczy. Więc po prostu niszczy informacje.
W moim ulubionym eksperymencie o zerowej myśli proszę o wyobrażenie sobie złożonej maszyny Rube Goldbergian , która sygnalizuje zakodowane wiadomości za pomocą kolorowego światła, podnosząc kolorowe żarówki z przenośnika taśmowego, wkręcając je w gniazdo i zasilając je. Sygnał jest kontrolowany przez różne kolory żarówek umieszczonych na taśmie przenośnika.
Poproszono Cię o uczynienie tej ohydnie drogiej rzeczy zgodnej z RFC3.14159, która stwierdza, że pomiędzy wiadomościami powinien znajdować się znacznik. Znacznik nie powinien być wcale światłem. Powinien trwać dokładnie jeden impuls. Tyle samo czasu, co zwykle świeci jedno kolorowe światło.
Nie możesz po prostu zostawić spacji między wiadomościami, ponieważ urządzenie uruchamia alarmy i zatrzymuje się, jeśli nie może znaleźć żarówki do włożenia do gniazda.
Wszyscy zaznajomieni z tym projektem drżą na myśl o dotknięciu maszyny lub jej kodu sterującego. Zmiana nie jest łatwa. Co robisz? Możesz zanurzyć się i zacząć niszczyć rzeczy. Może zaktualizuj te rzeczy ohydne wzornictwo. Tak, możesz to zrobić o wiele lepiej. Możesz też porozmawiać z dozorcą i zacząć zbierać spalone żarówki.
To rozwiązanie polimorficzne. System nie musi nawet wiedzieć, że coś się zmieniło.
To naprawdę miłe, jeśli możesz to zrobić. Kodując znaczące odrzucenie założenia w wartość, nie musisz zmuszać pytania do zmiany.
Ile jabłek będziesz mi winien, jeśli dam ci 1 jabłko? -1. Ponieważ byłam ci winna 2 jabłka z wczoraj. Tutaj założenie pytania „jesteś mi winien” jest odrzucone liczbą ujemną. Mimo że pytanie było błędne, w tej odpowiedzi zakodowane są znaczące informacje. Odrzucając je w znaczący sposób, pytanie nie jest zmuszane do zmiany.
Czasami jednak zmiana pytania jest właściwą drogą. Jeśli założenie może być bardziej wiarygodne, a jednocześnie przydatne, rozważ to.
Problem polega na tym, że zwykle aktualizacje pochodzą od graczy. Ale odkryłeś potrzebę aktualizacji, która nie pochodzi od odtwarzacza 1 lub odtwarzacza 2. Potrzebujesz aktualizacji z informacją, że upłynął czas. Żaden z graczy tego nie mówi, więc co powinieneś zrobić? Pozostawienie gracza zerowego wydaje się takie kuszące. Ale niszczy informacje. Próbujesz zakodować wiedzę w czarnej dziurze.
Pole gracza nie mówi, kto się właśnie przeprowadził. Myślisz, że tak, ale ten problem dowodzi, że to kłamstwo. Pole gracza informuje, skąd pochodzi aktualizacja. Aktualizacja, której upłynął czas, pochodzi z zegara gry. Moim zaleceniem jest nadanie zegarowi zasługi, na jaką zasługuje, i zmiana nazwy
player
pola na coś podobnegosource
.W ten sposób, jeśli serwer się wyłącza i musi zawiesić grę, może wysłać aktualizację, która informuje o tym, co się dzieje, i podaje się jako źródło aktualizacji.
Czy to oznacza, że nigdy nie powinieneś po prostu coś pomijać? Nie. Ale musisz wziąć pod uwagę, jak dobrze nie można założyć, że naprawdę oznacza pojedynczą dobrze znaną dobrą wartość domyślną. Nie jest tak naprawdę zbyt łatwe w użyciu. Dlatego zachowaj ostrożność podczas korzystania z niego. Istnieje szkoła myślenia, która nie sprzyja niczym . Nazywa się to konwencją nad konfiguracją .
Sam to lubię, ale tylko wtedy, gdy konwencja jest w jakiś sposób jasno zakomunikowana. Nie powinno to być sposobem na zmylenie nowicjuszy. Ale nawet jeśli tego używasz, null wciąż nie jest najlepszym sposobem na zrobienie tego. Null jest niebezpiecznym niczym . Null udaje, że można z niego korzystać aż do momentu użycia, a następnie wysadza dziurę we wszechświecie (psuje model semantyczny). Chyba że zachowanie jest potrzebne, chyba że zrujnowanie dziury we wszechświecie jest powodem, dla którego masz z tym problem? Użyj czegoś innego.
źródło
null
tak naprawdę nie jest tutaj problemem. Problem polega na tym, jak większość obecnych języków programowania radzi sobie z brakującymi informacjami; nie traktują tego problemu poważnie (lub przynajmniej nie zapewniają wsparcia i bezpieczeństwa, których większość ziemian potrzebuje, aby uniknąć pułapek). Prowadzi to do wszystkich problemów, których nauczyliśmy się bać (wyjątek Java NullPointerException, Segfaults ...).Zobaczmy, jak lepiej poradzić sobie z tym problemem.
Inni sugerowali wzorzec zerowego obiektu . Chociaż wydaje mi się, że ma to czasem zastosowanie, istnieje wiele scenariuszy, w których nie ma tylko jednej wartości domyślnej dla jednego rozmiaru. W takich przypadkach konsumenci ewentualnie nieobecnych informacji muszą mieć możliwość samodzielnego podjęcia decyzji, co zrobić, jeśli brakuje tych informacji.
Istnieją języki programowania, które zapewniają bezpieczeństwo przed wskaźnikami zerowymi (tzw. Void security) w czasie kompilacji. Podam kilka współczesnych przykładów: Kotlin, Rust, Swift. W tych językach problem braku informacji został potraktowany poważnie, a użycie wartości null jest całkowicie bezbolesne - kompilator powstrzyma cię od wyłuskiwania zerowych punktów.
W Javie podjęto starania, aby ustanowić adnotacje @ Nullable / @ NotNull wraz z kompilatorem + wtyczki IDE, aby osiągnąć ten sam efekt. To nie było tak naprawdę udane, ale to nie wchodzi w zakres tej odpowiedzi.
Wyraźny, ogólny typ oznaczający możliwą nieobecność jest innym sposobem na poradzenie sobie z tym. Np. W Javie jest
java.util.Optional
. Może działać:na poziomie projektu lub firmy możesz ustalić zasady / wytyczne
java.util.Optional
zamiastnull
Twoja społeczność / ekosystem językowy wymyślił inne sposoby rozwiązania tego problemu lepiej niż kompilator / tłumacz.
źródło
Optional.isPresent
isPresent()
nie jest zalecanym użyciem OpcjonalnegoNie widzę żadnej wartości w stwierdzeniu, że wartość null jest zła. Sprawdziłem dyskusje na ten temat, a one tylko niecierpliwiły mnie i irytowały.
Null może być źle użyty, jako „magiczna wartość”, gdy w rzeczywistości coś znaczy. Ale aby się tam dostać, musiałbyś zrobić trochę pokręconego programowania.
Wartość null powinna oznaczać „nie ma”, która nie została utworzona (jeszcze) lub (już) nie ma lub nie została podana, jeśli jest argumentem. To nie jest stan, brakuje całej rzeczy. W ustawieniu OO, w którym rzeczy są tworzone i niszczone przez cały czas, jest to ważny, znaczący warunek różny od dowolnego stanu.
Nie do końca prawda, mogę otrzymać ostrzeżenie, aby nie sprawdzać wartości null przed użyciem zmiennej. I to nie to samo. Mogę nie chcieć oszczędzać zasobów obiektu, który nie ma celu. A co ważniejsze, będę musiał sprawdzić alternatywę tak samo, aby uzyskać pożądane zachowanie. Jeśli zapomnę to zrobić, wolę uzyskać NullReferenceException w czasie wykonywania niż jakieś nieokreślone / niezamierzone zachowanie.
Jest jeden problem, o którym należy pamiętać. W kontekście wielowątkowym należałoby zabezpieczyć się przed warunkami wyścigu, przypisując zmienną lokalną przed wykonaniem sprawdzenia wartości null.
Nie, to nic nie powinno znaczyć, więc nie ma co niszczyć. Nazwa i typ zmiennej / argumentu zawsze powie, czego brakuje, to wszystko, co trzeba wiedzieć.
Edytować:
Jestem w połowie drogi do filmu candied_orange połączonego z jedną z jego innych odpowiedzi na temat programowania funkcjonalnego i jest to bardzo interesujące. Widzę jego przydatność w niektórych scenariuszach. Podejście funkcjonalne, które do tej pory widziałem, z latającymi fragmentami kodu, zwykle powoduje, że kulę się, gdy jestem używany w ustawieniach OO. Ale chyba ma swoje miejsce. Gdzieś. I wydaje mi się, że będą języki, które wykonają dobrą robotę, ukrywając to, co uważam za mylący bałagan, ilekroć napotykam go w C #, języki, które zapewniają czysty i sprawny model.
Jeśli ten model funkcjonalny jest twoim umysłem / frameworkiem, tak naprawdę nie ma alternatywy dla popychania jakichkolwiek wpadek do przodu jako udokumentowanych opisów błędów i ostatecznie pozwól, aby osoba dzwoniąca poradziła sobie z nagromadzonymi śmieciami, które zostały przeciągnięte aż do momentu inicjacji. Najwyraźniej tak właśnie działa programowanie funkcjonalne. Nazwij to ograniczeniem, nazwij to nowym paradygmatem. Możesz uznać, że jest to hack dla funkcjonalnych uczniów, który pozwala im dalej iść na nieświętą ścieżkę, możesz być zachwycony tym nowym sposobem programowania, który uwalnia nowe ekscytujące możliwości. Cokolwiek, wydaje mi się bezcelowe wkraczanie w ten świat, wskazywanie na tradycyjny sposób robienia rzeczy przez OO (tak, możemy rzucać wyjątki, przepraszam), wybranie z tego jakiejś koncepcji
Każda koncepcja może być użyta w niewłaściwy sposób. Z mojego punktu widzenia prezentowane „rozwiązania” nie stanowią alternatywy dla właściwego użycia zer. Są to koncepcje z innego świata.
źródło
None
reprezentuje….Twoje pytanie.
W pełni tam na pokładzie. Są jednak pewne zastrzeżenia, które omówię za chwilę. Ale najpierw:
Myślę, że jest to oświadczenie o dobrych intencjach, ale zbyt ogólne.
Nulls nie są złe. Nie są antypatternem. Nie należy ich za wszelką cenę unikać. Jednak wartości null są podatne na błędy (od braku sprawdzenia wartości null).
Ale nie rozumiem, w jaki sposób brak sprawdzenia wartości null jest dowodem, że użycie wartości null jest z natury niewłaściwe.
Jeśli wartość null jest zła, to również indeksy tablic i wskaźniki C ++. Oni nie są. Łatwo jest strzelać sobie w stopę, ale nie należy ich unikać za wszelką cenę.
W pozostałej części tej odpowiedzi zamierzam dostosować zamiar „zerowe są złe” do bardziej dopracowanych „ zerowych należy traktować odpowiedzialnie ”.
Twoje rozwiązanie
Chociaż zgadzam się z twoją opinią na temat stosowania wartości null jako reguły globalnej; W tym konkretnym przypadku nie zgadzam się z użyciem przez Ciebie wartości null.
Podsumowując poniższe opinie: nie rozumiesz celu dziedziczenia i polimorfizmu. Podczas gdy twój argument, aby użyć null, jest ważny, twój dalszy „dowód”, dlaczego drugi sposób jest zły, opiera się na niewłaściwym wykorzystaniu dziedziczenia, co czyni twoje punkty nieco nieistotnymi dla problemu zerowego.
Jeśli te aktualizacje są znacząco różne (którymi są), potrzebne są dwa osobne typy aktualizacji.
Weźmy na przykład wiadomości. Masz komunikaty o błędach i wiadomości czatu IM. Ale chociaż mogą zawierać bardzo podobne dane (komunikat w postaci ciągu i nadawcę), nie zachowują się w ten sam sposób. Powinny być używane osobno, jako różne klasy.
To, co teraz robisz, polega na rozróżnieniu dwóch typów aktualizacji na podstawie nieważności właściwości Player. Jest to równoważne z podejmowaniem decyzji między komunikatem IM a komunikatem o błędzie na podstawie istnienia kodu błędu. Działa, ale nie jest to najlepsze podejście.
Twój argument opiera się na wadach polimorfizmu. Jeśli masz metodę, która zwraca
GameUpdate
obiekt, generalnie nie powinno się nigdy starać rozróżniaćGameUpdate
,PlayerGameUpdate
lubNewlyDevelopedGameUpdate
.Klasa podstawowa musi mieć w pełni działającą umowę, tzn. Jej właściwości są zdefiniowane w klasie podstawowej, a nie w klasie pochodnej (to powiedziawszy, wartość tych właściwości podstawowych można oczywiście zastąpić w klasach pochodnych).
To sprawia, że twój argument jest dyskusyjny. W dobrej praktyce nigdy nie powinieneś się przejmować, że twój
GameUpdate
obiekt ma lub nie ma gracza. Jeśli próbujesz uzyskać dostęp doPlayer
właściwości aGameUpdate
, robisz coś nielogicznego.Wpisane języki, takie jak C #, nawet nie pozwolą ci uzyskać dostępu do
Player
właściwości,GameUpdate
ponieważGameUpdate
po prostu nie ma tej właściwości. JavaScript jest znacznie bardziej luźny w swoim podejściu (i nie wymaga wstępnej kompilacji), więc nie zadaje sobie trudu, aby cię poprawić i zamiast tego powoduje wybuch w czasie wykonywania.Nie powinieneś tworzyć klas opartych na dodawaniu właściwości zerowalnych. Powinieneś tworzyć klasy w oparciu o funkcjonalnie unikalne typy aktualizacji gier .
Jak w ogóle uniknąć problemów z zerowym?
Uważam, że warto opracować sposób, w jaki można w sposób znaczący wyrazić brak wartości. Jest to zbiór rozwiązań (lub złych podejść) w dowolnej kolejności.
1. W każdym razie użyj null.
To jest najłatwiejsze podejście. Jednak rejestrujesz się, aby uzyskać mnóstwo kontroli zerowych i (gdy tego nie zrobisz) rozwiązywanie problemów z wyjątkami referencji zerowych.
2. Użyj niepustej wartości bez znaczenia
Prostym przykładem jest tutaj
indexOf()
:Zamiast tego
null
dostajesz-1
. Na poziomie technicznym jest to poprawna wartość całkowita. Jednak wartość ujemna to nonsensowna odpowiedź, ponieważ oczekuje się, że indeksy będą dodatnimi liczbami całkowitymi.Logicznie można tego użyć tylko w przypadkach, w których typ zwracany pozwala na więcej możliwych wartości, niż można je w sposób znaczący zwrócić (indexOf = liczby całkowite dodatnie; int = liczby całkowite ujemne i dodatnie)
W przypadku typów referencyjnych nadal można zastosować tę zasadę. Na przykład, jeśli masz encję o identyfikatorze całkowitym, możesz zwrócić fikcyjny obiekt o jego identyfikatorze ustawionym na -1, w przeciwieństwie do wartości null.
Musisz po prostu zdefiniować „stan obojętny”, za pomocą którego można zmierzyć, czy obiekt jest rzeczywiście użyteczny, czy nie.
Zauważ, że nie powinieneś polegać na ustalonych wcześniej wartościach ciągów, jeśli nie kontrolujesz wartości ciągów. Możesz rozważyć ustawienie nazwy użytkownika na „null”, gdy chcesz zwrócić pusty obiekt, ale możesz napotkać problemy, gdy Christopher Null zarejestruje się w Twojej usłudze .
3. Zamiast tego rzuć wyjątek.
Nie, po prostu nie. Wyjątki nie powinny być obsługiwane dla przepływu logicznego.
To powiedziawszy, istnieją pewne przypadki, w których nie chcesz ukryć wyjątku (zerowego odniesienia), ale raczej pokazać odpowiedni wyjątek. Na przykład:
Może to rzucić
PersonNotFoundException
(lub podobny), gdy nie ma osoby o identyfikatorze 123.W pewien sposób jest to dopuszczalne tylko w przypadkach, w których nie znalezienie przedmiotu uniemożliwia dalsze przetwarzanie. Jeśli nie można znaleźć przedmiotu, a aplikacja może być kontynuowana, NIGDY nie należy rzucać wyjątku . Nie mogę tego wystarczająco podkreślić.
źródło
Przyczyną, dla której wartości null są złe, nie jest to, że brakująca wartość jest kodowana jako null, ale że każda wartość odniesienia może być null. Jeśli masz C #, prawdopodobnie i tak się zgubiłeś. Nie widzę sensu, żeby używać Opcjonalnego, ponieważ typ odniesienia jest już opcjonalny. Ale w Javie są adnotacje @Notnull, które wydaje się być w stanie skonfigurować na poziomie pakietu , a następnie w przypadku wartości, których można pominąć, można użyć adnotacji @Nullable.
źródło
Wartości zerowe nie są złe, realistycznie nie ma sposobu na implementację żadnej z alternatyw, jeśli w pewnym momencie nie zajmiemy się czymś, co wygląda jak zero.
Jednak wartości zerowe są niebezpieczne . Podobnie jak w przypadku innych konstruktów niskiego poziomu, jeśli popełnisz błąd, nie ma nic, co mogłoby cię złapać.
Myślę, że istnieje wiele ważnych argumentów przeciwko wartości null:
Że jeśli jesteś już w domenie wysokiego poziomu, istnieją bezpieczniejsze wzorce niż przy użyciu modelu niskiego poziomu.
Jeśli nie potrzebujesz zalet systemu niskiego poziomu i nie jesteś przygotowany na odpowiednią ostrożność, być może nie powinieneś używać języka niskiego poziomu.
itp ...
Wszystkie są ważne i ponadto nie trzeba się starać pisać autorów i seterów itp. Jest to powszechny powód, aby nie stosować się do tej rady. Nic dziwnego, że wielu programistów doszło do wniosku, że wartości zerowe są niebezpieczne i leniwe (zła kombinacja!), Ale podobnie jak wiele innych „uniwersalnych” porad, nie są tak uniwersalne, jak się je wypowiada.
Dobrzy ludzie, którzy napisali ten język, myśleli, że będą dla kogoś przydatni. Jeśli rozumiesz zastrzeżenia i nadal uważasz, że są one odpowiednie dla Ciebie, nikt inny nie będzie wiedział nic lepszego.
źródło
Java ma
Optional
klasę z jawnąifPresent
+ lambda do bezpiecznego dostępu do dowolnej wartości. Można to również zrobić w JS:Widzieć to pytanie StackOverflow .
Nawiasem mówiąc: wielu purystów uzna to użycie za wątpliwe, ale nie sądzę. Istnieją funkcje opcjonalne.
źródło
java.lang.Optional
bycianull
?Optional.of(null)
wyjątek,Optional.ofNullable(null)
dałbyOptional.empty()
- wartość nieobecna .Optional<Type> a = null
?Optional<Optional<Type>> a = Optional.empty();
;) - Innymi słowy w JS (i innych językach) takie rzeczy nie będą możliwe. Zrobiłaby to Scala z wartościami domyślnymi. Java może z enum. JS wątpię:Optional<Type> a = Optional.empty();
.null
lub pustej, do dwóch plus kilka dodatkowych metod na umieszczonym obiekcie. To całkiem spore osiągnięcie.CAR Hoare nazwał nulls swoim „błędem miliarda dolarów”. Należy jednak zauważyć, że myślał, że rozwiązaniem nie jest „brak null nigdzie”, ale „domyślne wartości zerowe, a null tylko tam, gdzie są one semantycznie wymagane”.
Problem z wartością null w językach, które powtarzają swój błąd, polega na tym, że nie można powiedzieć, że funkcja oczekuje danych, które nie mają wartości null; jest zasadniczo niewrażliwy na język. Zmusza to funkcje do włączenia wielu niepotrzebnych zewnętrznych płyt kotłowych zajmujących się zerowaniem, a zapominanie o sprawdzeniu wartości zerowej jest częstym źródłem błędów.
Aby zhakować ten podstawowy brak ekspresji, niektóre społeczności (np. Społeczność Scala) nie używają wartości zerowej. W Scali, jeśli chcesz null wartości typu
T
, bierzesz argument typuOption[T]
, a jeśli chcesz wartość null, po prostu bierzeszT
. Jeśli ktoś poda zero w twoim kodzie, Twój kod wysadzi się w powietrze. Uważa się jednak, że kod wywołujący jest błędnym kodem.Option
jest całkiem dobrym zamiennikiem wartości null, ponieważ typowe wzorce obsługi wartości null są wyodrębniane do funkcji bibliotecznych takich jak.map(f)
lub.getOrElse(someDefault)
.źródło