Rozwiązanie zgodne z rzeczywistością w Javie: przeanalizuj 2 liczby z 2 ciągów, a następnie zwróć ich sumę

84

Całkiem głupie pytanie. Biorąc pod uwagę kod:

public static int sum(String a, String b) /* throws? WHAT? */ {
  int x = Integer.parseInt(a); // throws NumberFormatException
  int y = Integer.parseInt(b); // throws NumberFormatException
  return x + y;
}

Czy możesz powiedzieć, czy to dobra Java, czy nie? To, o czym mówię, NumberFormatExceptionjest niezaznaczonym wyjątkiem. Nie musisz określać tego jako części sum()podpisu. Co więcej, o ile rozumiem, idea niezaznaczonych wyjątków ma na celu tylko zasygnalizowanie, że implementacja programu jest nieprawidłowa, a co więcej, przechwytywanie niezaznaczonych wyjątków jest złym pomysłem, ponieważ jest to jak naprawianie złego programu w czasie wykonywania .

Czy ktoś mógłby wyjaśnić, czy:

  1. Powinienem określić NumberFormatExceptionjako część podpisu metody.
  2. Powinienem zdefiniować swój własny sprawdzony wyjątek ( BadDataException), obsłużyć NumberFormatExceptionwewnątrz metody i ponownie wyrzucić go jako BadDataException.
  3. Powinienem zdefiniować mój własny sprawdzony wyjątek ( BadDataException), zweryfikować oba ciągi w sposób podobny do wyrażeń regularnych i wyrzucić mój, BadDataExceptionjeśli nie pasuje.
  4. Twój pomysł?

Aktualizacja :

Wyobraź sobie, że to nie jest framework open source, którego powinieneś używać z jakiegoś powodu. Patrzysz na sygnaturę metody i myślisz - „OK, ona nigdy nie rzuca”. Pewnego dnia miałeś wyjątek. Jest to normalne?

Aktualizacja 2 :

Są komentarze, które mówią, że mój sum(String, String)projekt jest zły. Całkowicie się zgadzam, ale dla tych, którzy uważają, że pierwotny problem nigdy by się nie pojawił, gdybyśmy mieli dobry projekt, oto dodatkowe pytanie:

Definicja problemu jest następująca: masz źródło danych, w którym liczby są przechowywane jako Strings. Źródłem tym może być plik XML, strona internetowa, okno pulpitu z 2 polami edycji, cokolwiek.

Twoim celem jest zaimplementowanie logiki, która zajmuje te 2 Stringsekundy, konwertuje je na intsi wyświetla okno komunikatu „Suma to xxx”.

Bez względu na to, jakie podejście zastosujesz do zaprojektowania / wdrożenia tego, będziesz mieć następujące 2 punkty wewnętrznej funkcjonalności :

  1. To miejsce, gdzie można przekonwertować Stringdoint
  2. Miejsce, w którym dodajesz 2 ints

Podstawowym pytaniem dotyczącym mojego oryginalnego posta jest:

Integer.parseInt()oczekuje przekazania poprawnego ciągu. Ilekroć przekażesz zły ciąg , oznacza to, że twój program jest nieprawidłowy (a nie „ twój użytkownik jest idiotą”). Musisz zaimplementować fragment kodu, w którym z jednej strony masz Integer.parseInt () z semantyką MUST, az drugiej strony musisz być OK z przypadkami, gdy dane wejściowe są niepoprawne - POWINIENEŚ semantykę .

A więc pokrótce: jak zaimplementować semantykę POWINIENEM, jeśli mam tylko MUSI biblioteki .

Andrey Agibalov
źródło
13
To wcale nie jest głupie pytanie. Właściwie to całkiem niezły! Nie jestem do końca pewien, którą opcję bym wybrał.
martin,
1
Do Twojej aktualizacji: Tak, zgodnie z zasadą szybkiego reagowania, to też niekoniecznie byłoby złe.
Johan Sjöberg,
1
Zgadzam się z Martinem. Jest to jeden z najmniej zrozumiałych aspektów programowania w Javie, który wymaga pewnych najlepszych praktyk. Świadczy o tym brak stron na ten temat, a poza O'Reilly'm bardzo niewiele mówi „tak to powinno być zrobione”.
James P.,
2
Właściwie to doskonałe pytanie.
Chris Cudmore,
1
Świetne pytanie! Również podniósł kilka świetnych odpowiedzi: D
Kheldar

Odpowiedzi:

35

To jest dobre pytanie. Chciałbym, żeby więcej ludzi myślało o takich rzeczach.

IMHO, rzucanie niezaznaczonych wyjątków jest dopuszczalne, jeśli przekazano parametry śmieci.

Ogólnie rzecz biorąc, nie powinieneś rzucać, BadDataExceptionponieważ nie powinieneś używać wyjątków do sterowania przepływem programu. Wyjątki dotyczą wyjątków. Wywołujące metodę mogą wiedzieć, zanim ją wywołają, czy ich ciągi są liczbami, czy nie, więc można uniknąć przekazywania śmieci i dlatego można je uznać za błąd programowania , co oznacza, że ​​można rzucać niezaznaczone wyjątki.

Odnośnie deklarowania throws NumberFormatException- nie jest to zbyt przydatne, ponieważ niewielu to zauważy z powodu odznaczenia NumberFormatException. Jednak IDE mogą z tego skorzystać i zaoferować try/catchprawidłowe zawijanie . Dobrym rozwiązaniem jest również użycie javadoc, np:

/**
 * Adds two string numbers
 * @param a
 * @param b
 * @return
 * @throws NumberFormatException if either of a or b is not an integer
 */
public static int sum(String a, String b) throws NumberFormatException {
    int x = Integer.parseInt(a); 
    int y = Integer.parseInt(b); 
    return x + y;
}

ZMIENIONO : Komentatorzy podali
ważne punkty. Musisz zastanowić się, jak to będzie używane i jaki jest ogólny projekt Twojej aplikacji.

Jeśli metoda będzie używana w każdym miejscu i ważne jest, aby wszyscy wywołujący radzili sobie z problemami, deklarują metodę jako rzucającą sprawdzony wyjątek (zmuszając wywołujące do radzenia sobie z problemami), ale zaśmiecając kod try/catchblokami.

Jeśli z drugiej strony używamy tej metody z danymi, którym ufamy, zadeklaruj ją jak powyżej, ponieważ nie oczekuje się, że kiedykolwiek wybuchnie i unikniesz bałaganu w kodzie w postaci niepotrzebnych try/catchbloków.

Czeski
źródło
6
Problem polega na tym, że niezaznaczone wyjątki są często ignorowane i mogą przenikać do stosu wywołań, siejąc spustoszenie w częściach aplikacji, które nie mają pojęcia, co kryje się pod spodem. Pytanie naprawdę brzmi, który bit kodu powinien sprawdzać, czy dane wejściowe są prawidłowe, czy nie.
G_H,
1
@G_H ma rację. Samouczki Javy mówią: „Jeśli można racjonalnie oczekiwać, że klient odzyska sprawność po wyjątku, uczyń go sprawdzonym wyjątkiem. Jeśli klient nie może nic zrobić, aby odzyskać dane z wyjątku, uczyń go niezaznaczonym wyjątkiem”. Pytanie brzmi, gdzie należy się RuntimeExceptionzająć? Czy powinien to być rozmówca, czy też należy pozostawić wyjątek, aby się unosił? Jeśli tak, jak należy sobie z tym radzić?
James P.,
1
Aby częściowo odpowiedzieć na to pytanie, widziałem dwa podejścia: pierwsze polega na przechwyceniu Exceptionsz niższych warstw i zawinięciu ich w wyższy poziom Wyjątki, które są bardziej znaczące dla użytkownika końcowego, a drugie polega na użyciu nieprzechwyconego modułu obsługi wyjątków, który można zainicjować w program uruchamiający aplikacje.
James P.,
2
IMHO posiadanie wyjątku NumberFormatException w javaDoc jest znacznie ważniejsze. Umieszczenie go w throwsklauzuli jest miłym dodatkiem, ale nie jest wymagane.
Dorus,
3
Do „Osoby dzwoniące do Twojej metody mogą wiedzieć, zanim ją wywołają, czy ich łańcuchy są liczbami, czy nie, więc można uniknąć przekazywania śmieci” : To nieprawda. Jedynym prostym sposobem sprawdzenia, czy łańcuch jest analizowany jako int, jest jego wypróbowanie. Chociaż możesz chcieć zrobić kilka kontroli z góry, dokładne sprawdzenie to dość PITA.
maaartinus
49

Moim zdaniem byłoby lepiej obsługiwać logikę wyjątków tak daleko, jak to możliwe. Dlatego wolałbym podpis

 public static int sum(int a, int b);

Dzięki twojej metodzie niczego bym nie zmienił. Albo jesteś

  • Programowo przy użyciu niepoprawnych wartości, w których zamiast tego można zweryfikować algorytm producenta
  • lub wysyłanie wartości np. z danych wejściowych użytkownika, w którym to przypadku moduł powinien przeprowadzić walidację

Dlatego obsługa wyjątków w tym przypadku staje się kwestią dokumentacji .

Johan Sjöberg
źródło
4
Lubię to. Zmusza użytkownika do przestrzegania umowy i sprawia, że ​​metoda robi tylko jedną rzecz.
Chris Cudmore,
Nie rozumiem, czym różni się użycie tej metody od użytkownika wykonującego a + b. Dlaczego potrzebujemy tej metody?
Swati
4
@Swati: Myślę, że to przykład , który jest świetną techniką pokazania rzeczy w prosty sposób. Metoda suma mogłaby być równie dobrze myVeryComplicatedMethodWhichComputesPhoneNumberOfMyIdealMatchGirl (int myid, int myLifeExpectancy) ...
Kheldar
3
Całkowicie się tutaj zgadzam. sumfunkcja, która spodziewa się dwa numery, powinien dostać dwa numery. Sposób, w jaki je otrzymałeś, nie jest związany z sumfunkcją. Oddziel poprawnie logikę . Więc odniósłbym to do problemu projektowego.
c00kiemon5ter
5

Numer 4. Jak podano, ta metoda nie powinna przyjmować łańcuchów jako parametrów, a powinna przyjmować liczby całkowite. W takim przypadku (ponieważ java zawija się zamiast przepełniać) nie ma możliwości wystąpienia wyjątku.

 x = sum(Integer.parseInt(a), Integer.parseInt(b))

jest o wiele jaśniejsze, co to znaczy x = sum(a, b)

Chcesz, aby wyjątek występował jak najbliżej źródła (wejścia).

Jeśli chodzi o opcje 1-3, nie definiujesz wyjątku, ponieważ oczekujesz, że wywołujący zakładają, że w przeciwnym razie twój kod nie może zawieść, definiujesz wyjątek, aby zdefiniować, co dzieje się w znanych warunkach niepowodzenia, które są WYJĄTKOWE DLA TWOJEJ METODY. To znaczy, jeśli masz metodę, która jest opakowaniem wokół innego obiektu i zgłasza wyjątek, a następnie przekazuje go dalej. Tylko jeśli wyjątek jest unikalny dla twojej metody, powinieneś rzucić niestandardowy wyjątek (frex, w twoim przykładzie, jeśli suma miała zwracać tylko pozytywne wyniki, to sprawdzenie tego i zgłoszenie wyjątku byłoby właściwe, jeśli z drugiej strony java rzucił wyjątek przepełnienia zamiast zawijania, wtedy można go przekazać dalej, nie definiować go w swoim podpisie, zmieniać jego nazwy ani zjadać).

Aktualizacja w odpowiedzi na aktualizację pytania:

A więc pokrótce: jak zaimplementować semantykę POWINIENEM, jeśli mam tylko MUSI biblioteki.

Rozwiązaniem tego problemu jest zawinięcie biblioteki MUST i zwrócenie wartości SHOULD. W tym przypadku funkcja, która zwraca liczbę całkowitą. Napisz funkcję, która pobiera ciąg i zwraca obiekt Integer - albo działa, albo zwraca null (jak Ints.tryParse guawy). Wykonaj walidację oddzielnie od operacji, twoja operacja powinna mieć ints. To, czy twoja operacja zostanie wywołana z wartościami domyślnymi, gdy masz nieprawidłowe dane wejściowe, czy zrobisz coś innego, będzie zależeć od twoich specyfikacji - większość, co mogę o tym powiedzieć, to to, że jest naprawdę mało prawdopodobne, aby miejsce do podjęcia takiej decyzji było w operacji metoda.

jmoreno
źródło
Jaki jest twój pomysł? Otrzymam ten sam problem, nawet jeśli mam sum(int, int)i parseIntFromString(String). Aby uzyskać tę samą funkcjonalność, w obu przypadkach będę musiał napisać fragment kodu, w którym są 2 wywołania parseIntFromString()i 1 wywołanie sum(). Rozważ ten przypadek, jeśli ma to dla ciebie sens - nie widzę różnicy z punktu widzenia pierwotnego problemu.
Andrey Agibalov,
@ loki2302: chodzi o to, że dzwoniący decyduje, jakie zachowanie jest właściwe, gdy nie jest to numer. Ponadto, jeśli nie sprawdzają błędów, awaria występuje o krok bliżej miejsca przypisania wartości - dla celów debugowania im bliżej przypisania, tym łatwiejsze debugowanie. I bardziej prawdopodobne jest, że przegapisz napisanie odpowiedniego testu jednostkowego dla dzwoniącego, jeśli robisz TDD. Zasadniczo nie chcesz, aby w metodzie x był dostarczany łańcuch, który powinien być liczbą, a następnie 5 klas i 20 wywołań metod generuje wyjątek, gdy próbujesz traktować go jako liczbę.
jmoreno
Nie rozumiem. Czy próbujesz powiedzieć, że zapewnienie interfejsu int sum(String, String)w rzeczywistości nigdy nie jest możliwe?
Andrey Agibalov,
1
@ loki2302: Biorąc pod uwagę pokazany kod, byłby to możliwy, ale zły pomysł. Gdyby liczba w ciągu mogła być słowem, w którym „2”, „dwa”, „dos”, „deux”, „zwo” byłyby traktowane tak samo, wówczas taki podpis byłby odpowiedni. Ale tak jest, metoda otrzymuje dwa ciągi i traktuje je jako liczby całkowite. Dlaczego miałbyś kiedykolwiek chcieć to zrobić? To zły pomysł.
jmoreno,
2
@ loki2302: Zaakceptowałeś odpowiedź, mówiąc, że możesz rzucić niezaznaczony wyjątek, gdy mijałeś śmieci, ale celem silnie wpisanego języka jest ZAPOBIEGANIE przekazywaniu śmieci. Posiadanie metody, która oczekuje, że łańcuch zawsze będzie wartością całkowitą, jest po prostu pytaniem o kłopoty. Nawet Integer.parseInt nie radzi sobie tak dobrze (wyjątek dotyczący tego, czego POWINIENEŚ się spodziewać, jest zły, metoda integer.TryParse .Net jest znacznie lepsza, chociaż brak parametru out w Javie sprawia, że ​​jest to nieco niepraktyczne).
jmoreno
3

1. Powinienem podać NumberFormatException jako część podpisu metody.

Chyba tak. To niezła dokumentacja.

2. Powinienem zdefiniować własny sprawdzany wyjątek (BadDataException), obsłużyć NumberFormatException w metodzie i wyrzucić go ponownie jako BadDataException.

Czasem tak. Zaznaczone wyjątki są uważane za lepsze w niektórych przypadkach, ale praca z nimi to dość PITA. Dlatego wiele frameworków (np. Hibernate) używa tylko wyjątków czasu wykonywania.

3. Powinienem zdefiniować własny sprawdzany wyjątek (BadDataException), zweryfikować oba ciągi w sposób podobny do wyrażeń regularnych i wyrzucić mój BadDataException, jeśli nie pasuje.

Nigdy. Więcej pracy, mniejsza prędkość (chyba że spodziewasz się, że rzucanie wyjątku będzie regułą) i żadnego zysku.

4. Twój pomysł?

Wcale.

maaartinus
źródło
2

Nr 4.

Myślę, że w ogóle nie zmieniłbym metody. Położyłbym próbę złapania wokół metody wywoływania lub wyżej w śledzeniu stosu, gdzie jestem w kontekście, w którym mogę wdzięcznie odzyskać logikę biznesową z wyjątku.

Nie zrobiłbym tego na pewno, ponieważ uważam, że to przesada.

Farmor
źródło
2

Zakładając, że to, co piszesz, będzie używane (np. Jako API) przez kogoś innego, powinieneś wybrać 1, NumberFormatException jest specjalnie przeznaczony do komunikowania takich wyjątków i powinien być używany.

Ashkan Aryan
źródło
2
  1. Najpierw musisz zapytać siebie, czy użytkownik mojej metody musi się martwić o wprowadzenie błędnych danych, czy też oczekuje się od niego wprowadzenia odpowiednich danych (w tym przypadku String). To oczekiwanie jest również znane jako projekt na podstawie umowy .

  2. i 3. Tak, prawdopodobnie powinieneś zdefiniować BadDataException lub nawet lepiej użyć niektórych z wykluczających, takich jak NumberFormatException, ale raczej pozostawić standardowy komunikat do pokazania. Złap wyjątek NumberFormatException w metodzie i wyślij go ponownie wraz z komunikatem, nie zapominając o dołączeniu oryginalnego śladu stosu.

  3. Zależy to od sytuacji, ale prawdopodobnie wybrałbym ponownie wyjątek NumberFormatException z dodatkowymi informacjami. Musi również istnieć wyjaśnienie javadoc dotyczące oczekiwanych wartościString a, String b

Mite Mitreski
źródło
1

Wiele zależy od scenariusza, w którym się znajdujesz.

Przypadek 1. Zawsze debugujesz kod i nikt inny i wyjątek nie spowodują złego doświadczenia użytkownika

Wyrzuć domyślny wyjątek NumberFormatException

Przypadek 2: Kod powinien być łatwy w utrzymaniu i zrozumiały

Zdefiniuj własny wyjątek i dodaj o wiele więcej danych do debugowania podczas jego przesyłania.

Nie potrzebujesz sprawdzania wyrażeń regularnych, ponieważ i tak przejdzie do wyjątku przy złym wejściu.

Gdyby był to kod na poziomie produkcyjnym, moim pomysłem byłoby zdefiniowanie więcej niż jednego niestandardowego wyjątku, na przykład

  1. Wyjątek formatu liczb
  2. Wyjątek przepełnienia
  3. Wyjątek zerowy itp ...

i zajmij się tym wszystkimi osobno

Adithya Surampudi
źródło
1
  1. Możesz to zrobić, aby wyjaśnić, że może się to zdarzyć w przypadku nieprawidłowego wprowadzenia. Może pomóc komuś, kto używa Twojego kodu, aby zapamiętać obsługę tej sytuacji. Mówiąc dokładniej, dajesz do zrozumienia, że ​​sam nie obsługujesz tego w kodzie lub zamiast tego zwracasz określoną wartość. Oczywiście JavaDoc również powinien to wyjaśnić.
  2. Tylko wtedy, gdy chcesz zmusić rozmówcę do obsługi zaznaczonego wyjątku.
  3. To wydaje się przesada. Polegaj na analizie, aby wykryć błędne dane wejściowe.

Ogólnie rzecz biorąc, NumberFormaException nie jest zaznaczony, ponieważ oczekuje się, że zapewniono poprawnie analizowalne dane wejściowe. Walidacja danych wejściowych jest czymś, z czym powinieneś się zająć. Jednak w rzeczywistości analizowanie danych wejściowych jest najłatwiejszym sposobem na zrobienie tego. Możesz po prostu pozostawić swoją metodę bez zmian i ostrzec w dokumentacji, że oczekiwane są prawidłowe dane wejściowe i każdy wywołujący twoją funkcję powinien sprawdzić poprawność obu danych wejściowych przed jej użyciem.

G_H
źródło
1

Wszelkie wyjątkowe zachowania należy wyjaśnić w dokumentacji. Powinien albo wskazywać, że ta metoda zwraca specjalną wartość w przypadku niepowodzenia (np. nullPoprzez zmianę typu zwracanego na Integer), albo należy użyć przypadku 1. Umieszczenie go w sygnaturze metody pozwala użytkownikowi zignorować go, jeśli zapewni poprawne ciągi w inny sposób, ale nadal jest oczywiste, że metoda sama nie radzi sobie z tego rodzaju niepowodzeniem.

kapex
źródło
1

Odpowiedz na zaktualizowane pytanie.

Tak, to zupełnie normalne, że pojawiają się „niespodzianki”. Pomyśl o wszystkich błędach w czasie wykonywania, które pojawiły się, gdy jesteś nowy w programowaniu.

e.g ArrayIndexOutofBound

Również częsty wyjątek zaskoczenia z pętli for.

ConcurrentModificationException or something like that
Farmor
źródło
1

Chociaż zgadzam się z odpowiedzią, że wyjątek środowiska uruchomieniowego powinien być poddawany perkolacji, z punktu widzenia projektu i użyteczności, dobrym pomysłem byłoby umieszczenie go w wyjątku IllegalArgumentException zamiast wrzucania go jako NumberFormatException. To sprawia, że ​​kontrakt twojej metody jest bardziej przejrzysty, przez co deklaruje, że został do niej przekazany niedozwolony argument, z powodu którego rzuciła wyjątek.

Jeśli chodzi o aktualizację pytania „Wyobraź sobie, to nie jest framework open source, którego powinieneś używać z jakiegoś powodu. Patrzysz na sygnaturę metody i myślisz -„ OK, to nigdy nie rzuca ”. Potem pewnego dnia pojawił się wyjątek . Jest to normalne?" javadoc twojej metody powinien zawsze ujawniać zachowanie twojej metody (ograniczenia przed i po). Pomyśl o wierszach interfejsów say collection, gdzie jeśli wartość null nie jest dozwolona, ​​javadoc mówi, że zostanie zgłoszony wyjątek wskaźnika zerowego, chociaż nigdy nie jest on częścią sygnatury metody.

Skorpion
źródło
2
NumberFormatException jest podklasą IllegalArgumentException, więc to opakowanie nie dodaje żadnych informacji.
Don Roby,
co to znaczy, że wyjątek może zostać przeniesiony tak, jak jest (jak w tym przypadku nfe jest już niedozwolonym wyjątkiem argumentu) i może istnieć ogólna obsługa do obsługi nielegalnych argumentów gdzieś w hierarchii wywołań. więc jeśli byłby to przykład, w którym argumenty zostały przekazane przez użytkownika, mógłby istnieć ogólny kod, który opakowałby całą obsługę niedozwolonych argumentów i poinformowałby o tym użytkownika.
Scorpion,
1

Skoro mówisz o dobrej praktyce w Javie, moim zdaniem zawsze jest lepiej

  • Aby obsłużyć niezaznaczony wyjątek, przeanalizuj go i wykorzystaj niestandardowy niezaznaczony wyjątek.

  • Również podczas rzucania niestandardowego niezaznaczonego wyjątku można dodać komunikat o wyjątku, który klient może zrozumieć, a także wydrukować ślad stosu oryginalnego wyjątku

  • Nie ma potrzeby deklarowania wyjątku niestandardowego jako „rzutów”, ponieważ jest on niezaznaczony.

  • W ten sposób nie naruszasz użycia tego, do czego służą niezaznaczone wyjątki, a jednocześnie klient kodu z łatwością zrozumie przyczynę i rozwiązanie wyjątku.

  • Również prawidłowe dokumentowanie w java-doc jest dobrą praktyką i bardzo pomaga.

samarth
źródło
1

Myślę, że zależy to od twojego celu, ale udokumentowałbym to jako minimum:

/**
 * @return the sum (as an int) of the two strings
 * @throws NumberFormatException if either string can't be converted to an Integer
 */
public static int sum(String a, String b)
  int x = Integer.parseInt(a);
  int y = Integer.parseInt(b);
  return x + y;
}

Możesz też pobrać stronę z kodu źródłowego Java dla klasy java.lang.Integer:

public static int parseInt(java.lang.String string) throws java.lang.NumberFormatException;
Chris Knight
źródło
1

A co z wzorcem sprawdzania poprawności danych wejściowych zaimplementowanym przez bibliotekę Google „Guava” lub bibliotekę „Validator” Apache ( porównanie )?

Z mojego doświadczenia wynika, że ​​dobrą praktyką jest sprawdzanie poprawności parametrów funkcji na początku funkcji i zgłaszanie wyjątków tam, gdzie to konieczne.

Uważam również, że to pytanie jest w dużej mierze niezależne od języka. „Dobra praktyka” miałaby tutaj zastosowanie do wszystkich języków, które mają funkcje, które mogą przyjmować parametry, które mogą być prawidłowe lub nie.

Spycho
źródło
1

Myślę, że twoje pierwsze zdanie w „Dość głupie pytanie” jest bardzo istotne. Dlaczego w ogóle miałbyś napisać metodę z tym podpisem? Czy w ogóle ma sens sumowanie dwóch ciągów? Jeśli metoda wywołująca chce zsumować dwa ciągi, obowiązkiem metody wywołującej jest upewnienie się, że są one prawidłowe i przekonwertowanie ich przed wywołaniem metody.

W tym przykładzie, jeśli metoda wywołująca nie może przekonwertować dwóch ciągów znaków na int, może zrobić kilka rzeczy. To naprawdę zależy, w jakiej warstwie zachodzi to sumowanie. Zakładam, że konwersja String byłaby bardzo zbliżona do kodu front-end (jeśli została wykonana poprawnie), w takim przypadku 1. byłby najbardziej prawdopodobny:

  1. Ustaw komunikat o błędzie i zatrzymaj przetwarzanie lub przekieruj do strony błędu
  2. Zwróć fałsz (tj. Umieściłby sumę w jakimś innym obiekcie i nie byłby zobowiązany do jej zwrócenia)
  3. Dodaj wyjątek BadDataException, jak sugerujesz, ale jeśli sumowanie tych dwóch liczb nie jest bardzo ważne, jest to przesada i jak wspomniano powyżej, prawdopodobnie jest to zły projekt, ponieważ oznacza, że ​​konwersja jest wykonywana w niewłaściwym miejscu
GreenieMeanie
źródło
1

Jest wiele interesujących odpowiedzi na to pytanie. Ale nadal chcę to dodać:

Do analizowania ciągów zawsze wolę używać „wyrażeń regularnych”. Pakiet java.util.regex służy nam pomocą. Więc skończę z czymś takim, co nigdy nie stanowi żadnego wyjątku. Ode mnie zależy zwrócenie specjalnej wartości, jeśli chcę złapać jakiś błąd:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public static int sum(String a, String b) {
  final String REGEX = "\\d"; // a single digit
  Pattern pattern = Pattern.compile(REGEX);
  Matcher matcher = pattern.matcher(a);
  if (matcher.find()) { x = Integer.matcher.group(); }
  Matcher matcher = pattern.matcher(b);
  if (matcher.find()) { y = Integer.matcher.group(); }
  return x + y;
}

Jak widać, kod jest tylko trochę dłuższy, ale możemy sobie poradzić z tym, co chcemy (i ustawić wartości domyślne dla x i y, kontrolować, co się dzieje z klauzulami else itp.). Moglibyśmy nawet napisać bardziej ogólną transformację procedura, do której możemy przekazywać ciągi znaków, domyślne zwracane wartości, kod REGEX do kompilacji, komunikaty o błędach do wysyłania, ...

Mam nadzieję, że to było przydatne.

Ostrzeżenie: nie udało mi się przetestować tego kodu, więc przepraszam za ewentualne problemy ze składnią.

Louis
źródło
1
czy mówimy o Javie? Co to jest Integer.matcher? privatezmienna wewnątrz metody? Brakuje ()IFS, brakuje wiele ;, x, ynie zadeklarował, matcherogłosił dwa razy ...
user85421
Rzeczywiście Carlos, zrobiłem to w pośpiechu i jak powiedziałem, nie byłem w stanie tego od razu przetestować. Przepraszam. Chciałem pokazać sposób działania wyrażeń regularnych.
Louis
OK, ale to nie rozwiązuje problemu z NumberFormatException - główne pytanie IMO - (zakładając, że Integer.matcher.group()tak ma być Integer.parseInt(matcher.group()))
użytkownik85421
0

Napotykasz ten problem, ponieważ pozwalasz błędom użytkownika rozprzestrzeniać się zbyt głęboko do rdzenia aplikacji, a częściowo także dlatego, że nadużywasz typów danych Java.

Powinieneś mieć wyraźniejsze oddzielenie między walidacją danych wejściowych użytkownika a logiką biznesową, używać odpowiedniego wpisywania danych, a ten problem zniknie sam.

Faktem jest, że semantyka Integer.parseInt()jest znana - jej głównym celem jest analizowanie prawidłowych liczb całkowitych. Brakuje jawnego kroku weryfikacji / analizy danych wejściowych użytkownika.

rustyx
źródło