Buduję interfejs API, funkcję, która przesyła plik. Ta funkcja nie zwróci niczego / unieważni, jeśli plik został poprawnie przesłany i zgłasza wyjątek, gdy wystąpił jakiś problem.
Dlaczego wyjątek, a nie tylko fałsz? Ponieważ wewnątrz wyjątku mogę określić przyczynę niepowodzenia (brak połączenia, brak nazwy pliku, nieprawidłowe hasło, brak opisu pliku itp.). Chciałem zbudować niestandardowy wyjątek (z pewnym wyliczeniem, aby pomóc użytkownikowi interfejsu API obsłużyć wszystkie błędy).
Czy to dobra praktyka, czy też lepiej jest zwracać obiekt (z logiczną wartością wewnętrzną, opcjonalnym komunikatem o błędzie i wyliczeniem błędów)?
java
api-design
exceptions
functions
architectural-patterns
Accollativo
źródło
źródło
Result<T, E>
gdzieT
jest wynikiem, jeśli się powiedzie, iE
jest błędem, jeśli się nie powiedzie. Zgłoszenie wyjątku (może być - co nie jest tak pewne w Javie) może być kosztowne, ponieważ wymaga rozwinięcia stosu wywołań, ale utworzenie obiektu wyjątku jest tanie. Oczywiście trzymaj się ustalonych wzorców języka, którego używasz, ale nie łącz boolean i wyjątków takich jak ten.fillInStackTrace();
nazywa się superkonstruktorem w klasieThrowable
Odpowiedzi:
Zgłoszenie wyjątku jest po prostu dodatkowym sposobem, aby metoda zwróciła wartość. Dzwoniący może równie łatwo sprawdzić wartość zwracaną, jak złapać wyjątek i to sprawdzić. Dlatego przed podjęciem decyzji
throw
ireturn
wymaga innych kryteriów.Rzadkich wyjątków należy często unikać, jeśli zagraża to wydajności programu (konstruowanie obiektu wyjątku i odwijanie stosu wywołań to dla komputera znacznie więcej pracy niż tylko wypychanie na niego wartości). Ale jeśli celem Twojej metody jest przesłanie pliku, wąskim gardłem zawsze będzie we / wy sieci i systemu plików, więc optymalizacja metody zwrotu nie ma sensu.
Niewłaściwym pomysłem jest również wprowadzanie wyjątków dla tego, co powinno być prostym przepływem kontrolnym (np. Gdy wyszukiwanie zakończy się powodzeniem przez znalezienie jego wartości), ponieważ narusza to oczekiwania użytkowników API. Ale metoda, która nie spełnia swojego celu, jest wyjątkowym przypadkiem (a przynajmniej powinna być), więc nie widzę powodu, aby nie zgłaszać wyjątku. Jeśli to zrobisz, równie dobrze możesz uczynić go niestandardowym, bardziej informacyjnym wyjątkiem (ale dobrym pomysłem jest uczynienie go podklasą standardowego, bardziej ogólnego wyjątku, takiego jak
IOException
).źródło
Nie ma absolutnie żadnego powodu, aby powrócić
true
do sukcesu, jeśli nie powróciszfalse
w przypadku niepowodzenia. Jak powinien wyglądać kod klienta?W takim przypadku dzwoniący potrzebuje bloku try-catch, ale wtedy może lepiej napisać:
Zatem
true
wartość zwracana jest całkowicie nieistotna dla osoby dzwoniącej. Więc po prostu zachowaj metodęvoid
.Zasadniczo istnieją trzy sposoby projektowania trybów awaryjnych.
void
wyjątku „wyrzuć” (zaznaczone)Powrót
true
/false
Jest to używane w niektórych starszych interfejsach API, głównie typu C. Wady są obviuos, nie masz pojęcia, co poszło nie tak. PHP robi to dość często, co prowadzi do takiego kodu:
W kontekstach wielowątkowych jest jeszcze gorzej.
Zgłaszaj (zaznaczone) wyjątki
To dobry sposób na zrobienie tego. W niektórych momentach możesz spodziewać się niepowodzenia. Java robi to z gniazdami. Podstawowym założeniem jest, że połączenie powinno się powieść, ale wszyscy wiedzą, że niektóre operacje mogą się nie powieść. Wśród nich są połączenia gniazd. Dzwoniący zostaje zmuszony do obsługi awarii. jest to ładna konstrukcja, ponieważ zapewnia, że osoba dzwoniąca rzeczywiście poradzi sobie z awarią, i daje mu elegancki sposób radzenia sobie z awarią.
Zwraca wynikowy obiekt
To kolejny dobry sposób na poradzenie sobie z tym. Jest często używany do analizowania lub po prostu do sprawdzania poprawności.
Ładna, czysta logika dla dzwoniącego.
Trwa dyskusja, kiedy użyć drugiego przypadku, a kiedy trzeciego. Niektóre osoby uważają, że wyjątki powinny być wyjątkowe i że nie należy projektować z uwzględnieniem wyjątków i prawie zawsze będą korzystać z trzeciej opcji. W porządku Ale sprawdziliśmy wyjątki w Javie, więc nie widzę powodu, aby z nich nie korzystać. Używam sprawdzonych wyrażeń, gdy podstawowym założeniem jest, że wywołanie powinno zostać zakończone (jak użycie gniazda), ale niepowodzenie jest możliwe, i używam trzeciej opcji, gdy jest bardzo niejasne, że wywołanie powinno zostać zwiększone (jak sprawdzanie poprawności danych). Ale są na ten temat różne opinie.
W twoim przypadku wybrałbym
void
+Exception
. Oczekujesz, że przesyłanie pliku się zwiększy, a kiedy to zrobi, będzie wyjątkowe. Ale dzwoniący jest zmuszony obsłużyć ten tryb awarii i możesz zwrócić wyjątek, który poprawnie opisuje, jaki rodzaj błędu wystąpił.źródło
To naprawdę sprowadza się do tego, czy awaria jest wyjątkowa, czy oczekiwana .
Jeśli błąd nie jest czymś, czego zwykle się spodziewasz, jest prawdopodobne, że użytkownik API po prostu wywoła twoją metodę bez specjalnej obsługi błędów. Zgłoszenie wyjątku pozwala na podniesienie stosu do miejsca, w którym zostanie zauważony.
Jeśli z drugiej strony błędy są powszechne, należy zoptymalizować programistę, który je sprawdza, a
try-catch
klauzule są nieco bardziej kłopotliwe niż seriaif/elif
lubswitch
.Zawsze projektuj interfejs API w myśleniu osoby, która go używa.
źródło
Nie zwracaj wartości logicznej, jeśli nigdy nie zamierzasz wracać
false
. Po prostu stwórz metodęvoid
i dokument, że zgłosi wyjątek (IOException
odpowiedni) w przypadku niepowodzenia.Powodem tego jest to, że jeśli zwrócisz wartość logiczną, użytkownik Twojego interfejsu API może stwierdzić, że może to zrobić:
To oczywiście nie zadziała; oznacza to, że istnieje niezgodność między umową metody a jej zachowaniem. Jeśli zgłosisz sprawdzony wyjątek, użytkownik metody musi obsłużyć awarię:
źródło
Jeśli metoda ma wartość zwracaną, zgłoszenie wyjątku może zaskoczyć użytkowników. Jeśli widzę, że metoda zwraca wartość logiczną, jestem całkiem przekonany, że zwróci wartość prawda, jeśli się powiedzie, lub fałsz, jeśli nie, i utworzę strukturę kodu za pomocą klauzuli if-else. Jeśli Twój wyjątek i tak będzie oparty na wyliczeniu, możesz zamiast tego zwrócić wartość wyliczenia, podobnie jak w Windows HResults, i zachować wartość wyliczenia na wypadek, gdy metoda zakończy się powodzeniem.
Irytujące jest również wyjątek rzucania metod, gdy nie jest to ostatni krok procedury. Konieczność napisania try-catch i przekierowania kontroli do bloku catch to dobry przepis na spaghetti i należy go unikać.
Jeśli idziesz do przodu z wyjątkami, spróbuj zamiast tego anulować void, użytkownicy stwierdzą, że zakończy się sukcesem, jeśli nie zostaną zgłoszone żadne wyjątki, i żaden nie spróbuje użyć klauzuli if-else, aby zmienić kierunek kontroli.
źródło