2011-04-15 10 views
12

Tworzę bibliotekę zawierającą kilka metod analizowania dat i czasów napisów. Mam trudności z podjęciem decyzji o tym, jaki wyjątek powinny te metody wyrzucić, gdy argument łańcuchowy nie jest przetwarzalny. Jestem rozważa kilka opcji:Java API Design: NumberFormatException dla metody, która analizuje ciąg pół-numeryczny?

1. java.lang.IllegalArgumentException - nieprawidłowy ciąg jest wyraźnie nielegalne argumentem, ale dla mnie IllegalArgumentException zwykle oznacza błąd programowania, a to rzadko się chce zrobić wyraźne try catch jednego. Wydaje mi się, że analizowanie ciągów jest często dla danych wejściowych z zewnątrz i jest bardziej szczególnym przypadkiem, który zasługuje na specjalne traktowanie. Jeśli, powiedzmy, masz duży blok kodu, który analizował dane wprowadzone przez użytkownika i zrobił coś innego z tym, możesz chcieć zawinąć ten kod w bloku catch catch, aby móc obsłużyć przypadek danych wejściowych użytkownika zawierających niepoprawny ciąg znaków. Ale złapanie IllegalArgumentException nie byłoby zbyt dobre, aby wskazać nieprawidłowe dane wprowadzane przez użytkownika, ponieważ najprawdopodobniej w twoim kodzie znalazłoby się wiele miejsc, z których mógłby zostać wyrzucony (a nie tylko analizowanie danych wejściowych przez użytkownika).

2. java.lang.NumberFormatException - to rzucony przez Integer.parseInt(String) i innych podobnych metod analizowania w java.lang. Dlatego większość programistów Javy jest zaznajomiona z tym, że jest wyjątkiem do przechwytywania, gdy próbujesz przeanalizować ciąg znaków, który może być poprawny lub nie (np. Dane wejściowe użytkownika). Ale ma w nazwie "Numer", więc nie jestem pewien, czy rzeczywiście pasuje on do rzeczy takich jak daty i czasy, które są w pewnym sensie numeryczne, ale koncepcyjnie inne w moim umyśle. Jeśli tylko został nazwany "FormatException" ...

3. java.text.ParseException - nie jest to opcja, ponieważ jest zaznaczona. Chcę tego nie sprawdzać.

4. zwyczaj wyjątek - to robi wokół downsides z IllegalArgumentException i NumberFormatException, a to może przedłużyć IllegalArgumentException też. Ale nie wydaje mi się, że warto dodawać wyjątki do biblioteki, chyba że są naprawdę potrzebne. Cytując Josh Bloch, "If in doubt, leave it out". (Także w moim przypadku, dla pakietu, który analizuje daty i czasy, trudno nazwać taki wyjątek: "DateFormatException", "TimeFormatException", "CalendricalFormatException" (jak JSR 310) - żaden nie wydaje mi się idealny w zastosowaniu do metod które parsują daty, godziny, daty-czasy itd. I myślę, że byłoby głupio tworzyć wiele wyjątków w jednym pakiecie, gdyby wszystkie były używane tylko do identyfikacji ciągów nieodwracalnych.)

Którą z opcji uważasz za najbardziej odpowiednią? sens?

NB Mam dobre powody, dla których nie chcę używać java.util.Date lub Joda Time, lub JSR 310, więc nie ma potrzeby sugerowania tych. Plus myślę, że byłoby dobrze, gdyby to pytanie było dość ogólne, ponieważ musi to być problem, z którym borykają się inni projektanci interfejsów API. Daty i godziny mogą równie dobrze być adresami IP, adresami URL lub innymi rodzajami informacji, które mają formaty łańcuchów, które wymagają analizy.

precedensy ustawione przez inne biblioteki

tylko kilka przykładów znalazłem:

java.sql.Timestamp.valueOf(String) throws IllegalArgumentException

java.util.Date.parse(String) throws IllegalArgumentException (przestarzała metoda, i sytuacja ta nie jest zadeklarowana, ale można go zobaczyć w źródło)

java.util.UUID.fromString(String) throws IllegalArgumentException

org.apache.axis.types.Time(String) throws NumberFormatException (również klasa Dzień w Apache Axis)

org.apache.tools.ant.util.DeweyDecimal(String) throws NumberFormatException

com.google.gdata.data.DateTime.parseDateTime(String) throws NumberFormatException

java.lang.Package.isCompatibleWith(String versionString) throws NumberFormatException (w Java 7, trwa to kilka wersji ciąg z kropkami - trochę jak daty lub czasu w miłym sens)

Jestem pewien, że istnieje wiele pakietów, które używają niestandardowego wyjątku, więc wątpię, że jest dużo sensu w podawaniu ich przykładów.

Odpowiedz

0

Na to pytanie jest to kwestia gustu. Moim zdaniem nie wyrzucałbym wyjątku, ale w zamian za to odpowiadałam. Powodem jest to, że użytkownik nie może nic zrobić w obsłudze wyjątków, jeśli dane wejściowe były błędne. Tak więc tego typu błędy można łatwo rozwiązać, sprawdzając kod powrotu. Wyjątki są ciężkie i nie przynoszą dodatkowej wartości.

+2

zgadzam się wyjątki są ciężkie, ale ja zdecydowanie nie zgadzam się na uwzględnienie błędów w wartości zwracanej. To wymaga nadęty obiektów odpowiedzi lub powracający obiekt, z których oba mogą sprawić, że prosty interfejs API będzie bezużyteczny. –

+0

+1 @ sean-patrick-floyd: może zwrócić wartość null, następnie nadpis jest w kodzie, przez co staje się bezużyteczny. – subsub

+0

To naprawdę kwestia gustu. Zastanawiałem się nad wykorzystaniem metod takich jak parseOrNull (String), ale nie sądzę, że tak naprawdę pasuje do sposobu Java, który działa zgodnie z podstawowymi bibliotekami JDK. Poza tym zmuszasz ludzi do sprawdzania wartości zerowych lub uzyskują niepomocny wyjątek NullPointerException w przypadku, gdy analizują łańcuchy, które w 100% spodziewają się, że są poprawne (w przeciwieństwie do danych wprowadzanych przez użytkownika, gdy spodziewają się prawie wszystkiego). –

3

bym sugerował IllegalFormatException jako klasy bazowej (która dziedziczy z IllegalArgumentException, ale niestety jedynym Konstruktor Pakiet jest chroniona, więc pewnie bym użyć

  • IllegalArgumentException dla małym API (kilka metod)
  • swoją własną hierarchię klasy, która dziedziczy z IllegalArgumentException inaczej.

W każdym razie, chciałbym użyć jako podstawy IllegalArgumentException klasa.

W jednym z moich poprzednich projektów, wytyczną było tylko rzucać RuntimeExceptions które dziedziczą z

  • IllegalStateException
  • IllegalArgumentException
  • UnsupportedOperationException

Chociaż nie jest to oficjalny dogmat , Nazwałbym to dobrą praktyką. Wszystkie te trzy są proste i samoopisowe.

+0

Zrobiłem kontemplację bezpośrednio używając IllegalFormatException, ale istnieje tylko w Javie 1.5+, a ta biblioteka, którą piszę, jest zgodna z wersją 1.4. Począwszy od IllegalArgumentException może działać dobrze. Następnie, gdy biblioteka będzie rosła, nadal będę miał możliwość tworzenia i korzystania z podklasy bez naruszania kompatybilności. –

+0

@MB jak napisałem: nie można używać IllegalFormatException, nie ma dostępnego konstruktora –

+0

Ah tak, przepraszam. Z jakiegoś powodu, kiedy po raz pierwszy przeczytałem twój komentarz, zinterpretowałem to trochę, mówiąc, że IllegalFormatException nie może być przedłużony. Ale oczywiście tylko z prywatnym konstruktorem pakietów nie mogłem realistycznie go użyć. Nie widziałem drzewa dla drzew! –

1

Chciałbym wybrać ParseException, ponieważ to właśnie rzuca DateFormat.parse. Ma więc tę zaletę, o której wspomniałeś w 2., programiści go znają. Ale ponieważ chcesz odznaczyć, domyślam się, że to nie jest opcja. Jeśli zostanie wymuszony, aby przejść do niezaznaczonej, wybiorę 4.

+0

Familiar jest zdecydowanie dobry. Ale myślę, że sprawdzony wyjątek byłby dość uciążliwy dla tego rodzaju metody analizowania. Podobnie jak w przypadku analizowania liczb całkowitych, czasami należy przeanalizować dane wejściowe użytkownika, które prawdopodobnie są nieprawidłowe (a więc chcemy uchwycić i obsługiwać wyjątek jawnie), ale często analizujemy coś, co może być poprawne, a następnie trzeba się z nimi zapoznać. z zaznaczonym wyjątkiem byłoby bólem. –

+0

@MB: True. Jedną z rzeczy, które możesz zrobić, jest zapewnienie różnych funkcji dla tych dwóch przypadków, np. "Parsuj" dla pierwszego przypadku i "parseOrNull" lub "uncheckedParse" dla tego drugiego. Niestety (mam na myśli twój komentarz do parseOrNull poniżej), nie mogę wymyślić żadnego dobrego przykładu, w którym to robi interfejs Core Java API ... Nie jest to też zgodne z żadnymi zasadami KISS ani InDoubtLeaveItOut. – subsub

+0

Jeśli byłby to tylko do użytku wewnętrznego, prawdopodobnie bym to zrobił. 'parseOrNull' i' parseOrThrow' (wyrzucenie niesprawdzonego wyjątku, jeśli analiza nie powiodła się) jest tak naprawdę konwencją, której często używam.Ale nie sądzę, że byłoby to tak dobre dla publicznego API z powodów, o których wspomniałeś. Podejrzewam, że mogłoby to wprowadzić ludzi w błąd, ponieważ prawdopodobnie nie byłaby to konwencja, którą widzieli wcześniej, i naprawdę będą chcieli po prostu wykonać tę pracę JAK NAJSZYBCIEJ, zamiast poznawać moją terminologię. –

0

Obecnie jestem skłonny do korzystania z NumberFormatException.Myślałam zwykły stary IllegalArgumentException ale stało się dla mnie jasne, że to nie było idealne, gdy pisałem trochę kodu, takich jak:

try { 
    final Day day = Day.fromString(userInputString); 
    someMethodThatCouldAlsoThrowIllegalArgumentException(day); 
} catch (IllegalArgumentException e) { 
    ui.showWarningMessage("Invalid date: " + userInputString); 
} 

Zakładając, analizowania ważny Day, będziemy chcieli, aby coś z tym zrobić. Jest bardzo prawdopodobne, że metody, którym je przekażesz, wyrzucą IllegalArgumentException, jeśli otrzymają nieprawidłowy parametr (tj. Błąd programowania, a nie błąd użytkownika). W kodzie takim, jak powyższy przykład, chciałbyś uważać, aby nie pomylić błędu programowania z nieprawidłowym wprowadzeniem danych przez użytkownika, więc aby być po bezpiecznej stronie, potrzebujesz czegoś nieporządnego, jak zmienna pusta zdefiniowana przed blokiem try/catch i sprawdzenie po niej wartości zerowej.

Zamień IllegalArgumentException dla NumberFormatException lub niestandardowego wyjątku, a problem zniknie.

Widząc, że JDK 1.7 na java.lang.Package.isCompatibleWith(String versionNo) wykorzystuje NumberFormatException do metody, która analizuje numer wersji (ciąg semi-numeryczną jak "1.6.1.32"), myślę, że może to być również rozsądny wybór metod analizowania rzeczy jak daty i godziny.

nie jest idealnie idealny do analizowania łańcuchów, które są tylko pół-numeryczne, ale być może jest to najlepsza opcja, jeśli nie chcesz zaśmiecać interfejsu API niestandardowym wyjątkiem, który naprawdę nie jest potrzebny. Jeśli robią to w java.lang, to może to sprawia, że ​​sposób Java z robienia rzeczy z definicji ...

Mam nadzieję, że na łapie :)

Powiązane problemy