LBYL vs EAFP w Javie?

Niedawno uczyłem się Pythona i odkryłem idiomy LBYL / EAFP dotyczące sprawdzania błędów przed wykonaniem kodu. W Pythonie wydaje się, że akceptowanym stylem jest EAFP i wydaje się, że dobrze współpracuje z tym językiem.

LBYL (Look B efore Y ou L eap):

def safe_divide_1(x, y):
    if y == 0:
        print "Divide-by-0 attempt detected"
        return None
    else:
        return x/y

EAFP ( it 's E asier to A sk F orgiveness than P ermission):

def safe_divide_2(x, y):
    try:
        return x/y
    except ZeroDivisionError:  
        print "Divide-by-0 attempt detected"
        return None
Moje pytanie jest takie: nigdy nawet słyszałem o używaniu eafp jako podstawowej konstrukcji walidacji danych, pochodzącej z środowiska Java i C++. Czy EAFP jest czymś mądrym w Javie? A może jest zbyt dużo kosztów z WYJĄTKÓW? Wiem, że istnieje tylko wtedy, gdy wyjątek jest faktycznie wyrzucany, więc nie jestem pewien, dlaczego prostsza metoda EAFP nie jest używana. Czy to tylko Preferencje?
Author: Eric, 2009-01-01

5 answers

/ Align = "center" bgcolor = "# e0ffe0 " / cesarz chin / / align = center / Można spojrzeć na to jako odpowiednik następującego:

if (o != null)
    o.doSomething();
else
    // handle

W przeciwieństwie do:

try {
    o.doSomething()
}
catch (NullPointerException npe) { 
    // handle
}

Ponadto, rozważ, co następuje:

if (a != null)
    if (b != null)
        if (c != null)
            a.getB().getC().doSomething();
        else
            // handle c null
    else
        // handle b null
else
    // handle a null

Może to wyglądać o wiele mniej elegancko (i tak jest to prymitywny przykład - proszę mi wybaczyć), ale daje znacznie większą szczegółowość w obsłudze błędu, w przeciwieństwie do owijania go w próbę złapania go NullPointerException, a następnie spróbuj dowiedzieć się, gdzie i dlaczego go masz.

/ Align = "left" / Ponadto, skoro poruszyłeś ten problem: tak, blok try-catch powoduje pewne obciążenie , nawet jeśli wyjątek nie zostanie wyrzucony.
 5
Author: Yuval Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-01 11:17:14

Jeśli masz dostęp do plików, EAFP jest bardziej niezawodny niż LBYL, ponieważ operacje związane z LBYL nie są atomowe, a system plików może się zmieniać między czasem, w którym patrzysz, a czasem, w którym przeskakujesz. W rzeczywistości standardowa nazwa to Toctou-czas sprawdzania, czas użycia; błędy spowodowane niedokładnym sprawdzaniem są błędami TOCTOU.

Rozważ utworzenie pliku tymczasowego, który musi mieć unikalną nazwę. Najlepszym sposobem, aby dowiedzieć się, czy wybrana nazwa pliku Istnieje, jest jego utworzenie - upewnij się, że używasz opcji, aby upewnić się, że operacja nie powiedzie się, jeśli plik już istnieje (w terminach POSIX/Unix, flaga o_excl to open()). Jeśli spróbujesz sprawdzić, czy plik już istnieje( prawdopodobnie używając access()), to między czasem, w którym jest napisane "nie", a czasem, w którym próbujesz utworzyć plik, ktoś lub coś innego mogło go utworzyć.

Odwrotnie, Załóżmy, że próbujesz odczytać istniejący plik. Sprawdzenie czy plik istnieje (LBYL) może oznaczać "tam jest", ale gdy w rzeczywistości otwierasz go, znajdujesz "nie ma go tam".

W obu tych przypadkach musisz sprawdzić ostateczną operację - a LBYL nie pomógł automatycznie.

(Jeśli zadzierasz z programami SUID lub SGID, access() zadaje inne pytanie; może to być istotne dla LBYL, ale kod nadal musi uwzględniać możliwość niepowodzenia.)

 112
Author: Jonathan Leffler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-01 17:52:24

Oprócz względnego kosztu WYJĄTKÓW w Pythonie i Javie, należy pamiętać, że istnieje różnica w filozofii / nastawieniu między nimi. Java stara się być bardzo surowa w odniesieniu do typów (i wszystkiego innego), wymagając wyraźnych, szczegółowych deklaracji podpisów klas/metod. Zakłada ona, że w każdym momencie powinieneś wiedzieć dokładnie, jakiego rodzaju obiektu używasz i do czego jest on zdolny. Natomiast Python ' s "Duck typing" oznacza, że nie wiesz na pewno (i nie powinieneś care) jaki jest typ manifestu obiektu, musisz tylko dbać o to, aby kwakał, gdy go o to poprosisz. W tego rodzaju permisywnym środowisku jedynym rozsądnym podejściem jest zakładanie, że wszystko będzie działać, ale być gotowym do radzenia sobie z konsekwencjami, jeśli tego nie zrobią. naturalna restrykcyjność Javy nie pasuje dobrze do takiego dorywczego podejścia. (Nie ma to na celu dyskredytowania ani podejścia, ani języka, ale raczej stwierdzenie, że te postawy są częścią idiomu każdego języka i kopiowanie idiomów między różnymi językami często może prowadzić do niezręczności i złej komunikacji...)

 44
Author: Jeff Shannon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-02 23:31:52

Wyjątki są obsługiwane bardziej efektywnie w Pythonie niż w Javie, co jest przynajmniej częściowo dlaczego widzisz ten konstrukt w Pythonie. W Javie używanie WYJĄTKÓW w ten sposób jest bardziej nieefektywne (pod względem wydajności).

 10
Author: mipadi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-01 14:30:19

Rozważ te fragmenty kodu:

def int_or_default(x, default=0):
    if x.isdigit():
        return int(x)
    else:
        return default

def int_or_default(x, default=0):
    try:
        return int(x)
    except ValueError:
        return default
Obie wyglądają poprawnie, prawda? Ale jeden z nich nie jest.

Pierwszy, używając LBYL, nie powiedzie się z powodu subtelnego rozróżnienia między isdigit i isdecimal; gdy zostanie wywołany z łańcuchem "①23₅", wyrzuci błąd zamiast poprawnie zwrócić wartość domyślną.

Późniejsze, użycie EAFTP, z definicji skutkuje prawidłową obsługą. Nie ma możliwości niedopasowania zachowań, ponieważ kod, który wymaga wymogu , to kod, który potwierdza ten wymóg.

Użycie LBYL oznacza pobranie wewnętrznej logiki i skopiowanie jej do każdego miejsca wywołania. Zamiast mieć jedno kanoniczne kodowanie twoich wymagań, masz darmową szansę na bałagan za każdym razem, gdy wywołasz tę funkcję.

Warto zauważyć, że EAFTP nie jest o wyjątkach, a kod Javy szczególnie nie powinien używać WYJĄTKÓW. Chodzi o nadanie właściwej pracy właściwemu blokowi kodu. Jako przykład, użycie wartości zwracanych Optional jest doskonale poprawnym sposobem zapisu kodu EAFTP i jest o wiele bardziej skuteczne w zapewnianiu poprawności niż LBYL.

 2
Author: Veedrac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-28 18:26:54