Znajdź różnicę
06 Sep 2015Czasami niewielka różnica w kodzie może prowadzić do niespodziewanych konsekwencji, wynikających niekoniecznie z zawiłości logiki programu, ale z nieprzemyślanej konstrukcji języka lub środowiska programistycznego. Jeden ze sztandarowych przykładów, to pewna pułapka podczas przechwytywania wyjątków.
Zwróć uwagę na dwa przykłady:
Przykład pierwszy
Przykład drugi
Czym te przykłady się różnią?
Jedną linijką.
Instrukcją return
w bloku finally
.
Wydaje się, że tak niewielka zmiana nie powinna nic zepsuć, a psuje bardzo dużo, choć – wydawałoby się – nawet nie powinna zmienić działania programu. Spróbuj odpalić jeden i drugi przykład. W drugim wypadku wyjątek w ogóle nie zostanie wywołany i aplikacja zakończy się poprawnie.
Przykład trzeci
Nietrudno wyobrazić sobie sytuację, w której niedoświadczony programista w bloku try
pobiera coś z bazy danych, albo zewnętrznej usługi, generalnie wykonuje coś, co powinno przechwycić wyjątek.
Programista przeczytał niedawno jakiś artykuł Martina Fowlera i postanowił tworzyć kod zgodnie z zasadami Fluent Interface.
Dlatego na końcu każdej metody zwraca referencję do obiektu (this
).
Rozważmy przykład klasy, która ma służyć do pobierania prognozy pogody i aktualizacji ustawień klimatyzacji.
Na pierwszy rzut oka wszystko wygląda dobrze, a kod jest całkiem elegancki.
Metoda withTemperature
aktualizuje zapisaną temperaturę i… no właśnie.
Powinna wyrzucać wyjątek, jeśli nie da się takiej temperatury pobrać (błąd w nawiązywaniu połączenia, błąd pobierania, albo parsowania danych itp.).
W innym miejscu (tutaj metoda main
), pobierana jest temperatura z wykorzystaniem obiektu klasy WeatherDownloader
i na jej podstawie zmieniane są ustawienia klimatyzacji.
W przypadku braku dostępu do sieci, wyjątek powinien zapobiec zmianom ustawień klimatyzacji – jak zresztą opisuje to dokumentacja.
Tylko że przez głupi błąd wyjątek nie zostanie wyrzucony w metodzie withTemperature
i mamy problem.
Problem, który będzie bardzo trudno znaleźć.
Ponieważ nasz downloader nie jest niemutowalny (ale to już inna historia i inny problem), gdzieś w środku pewnie przechowywana jest zmienna, zawierająca temperaturę.
Zmienna prawdopodobnie przyjmie wartość 0.0
, albo może null
, w zależności od typu.
Ustawienia klimatyzatora zostaną błędnie skorygowane, ale dlaczego?
Przecież w logach nie pojawiła się informacja o tym, że nie pobrano temperatury.
Błąd więc musiał pojawić się w innym miejscu…