Jakie są przykłady z życia, aby zrozumieć kluczową rolę twierdzeń?
Jakie są przykłady z życia, aby zrozumieć kluczową rolę twierdzeń?
Odpowiedzi:
Asercje (za pomocą słowa kluczowego assert ) zostały dodane w Javie 1.4. Służą do weryfikacji poprawności niezmiennika w kodzie. Nigdy nie powinny być uruchamiane w kodzie produkcyjnym i wskazują na błąd lub niewłaściwe użycie ścieżki kodu. Można je aktywować w czasie wykonywania za pomocą -ea
opcji w java
poleceniu, ale domyślnie nie są włączone.
Przykład:
public Foo acquireFoo(int id) {
Foo result = null;
if (id > 50) {
result = fooService.read(id);
} else {
result = new Foo(id);
}
assert result != null;
return result;
}
assert
sprawdzać parametrów metody publicznej ( docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html ). To powinno rzucić Exception
zamiast zabijać program.
This convention is unaffected by the addition of the assert construct. Do not use assertions to check the parameters of a public method. An assert is inappropriate because the method guarantees that it will always enforce the argument checks. It must check its arguments whether or not assertions are enabled. Further, the assert construct does not throw an exception of the specified type. It can throw only an AssertionError.
docs.oracle.com/javase/8/docs/technotes/guides/language/…
Załóżmy, że masz napisać program do sterowania elektrownią jądrową. Jest oczywiste, że nawet najmniejszy błąd może mieć katastrofalne skutki, dlatego twój kod musi być wolny od błędów (zakładając, że JVM jest wolny od błędów dla samego argumentu).
Java nie jest językiem weryfikowalnym, co oznacza: nie można obliczyć, że wynik Twojej operacji będzie doskonały. Głównym tego powodem są wskaźniki: mogą wskazywać gdziekolwiek lub nigdzie, dlatego nie można ich obliczyć tak, aby miały tę dokładną wartość, przynajmniej nie w rozsądnym zakresie kodu. Biorąc pod uwagę ten problem, nie można w żaden sposób udowodnić, że kod jest poprawny. Ale co możesz zrobić, to udowodnić, że przynajmniej znajdziesz każdy błąd, kiedy to się stanie.
Pomysł ten oparty jest na paradygmacie Design-by-Contract (DbC): najpierw definiujesz (z matematyczną precyzją), co ma zrobić twoja metoda, a następnie weryfikujesz to, testując ją podczas faktycznego wykonania. Przykład:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
return a + b;
}
Chociaż jest to dość oczywiste, że działa dobrze, większość programistów nie zobaczy ukrytego błędu w tym (podpowiedź: Ariane V uległa awarii z powodu podobnego błędu). Teraz DbC definiuje, że zawsze musisz sprawdzić wejście i wyjście funkcji, aby sprawdzić, czy działała ona poprawnie. Java może to zrobić za pomocą asercji:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
assert (Integer.MAX_VALUE - a >= b) : "Value of " + a + " + " + b + " is too large to add.";
final int result = a + b;
assert (result - a == b) : "Sum of " + a + " + " + b + " returned wrong sum " + result;
return result;
}
Jeśli ta funkcja kiedykolwiek zawiedzie, zauważysz ją. Będziesz wiedział, że w kodzie jest problem, wiesz, gdzie on jest i wiesz, co go spowodowało (podobnie jak w wyjątkach). A co jeszcze ważniejsze: przestajesz wykonywać poprawnie, gdy tak się dzieje, aby uniemożliwić dalszemu kodowi pracę z nieprawidłowymi wartościami i potencjalnie spowodować uszkodzenie wszystkiego, co kontroluje.
Wyjątki Java są podobną koncepcją, ale nie wszystko weryfikują. Jeśli chcesz jeszcze więcej kontroli (kosztem szybkości wykonania), musisz użyć asercji. Spowoduje to wzdęcie kodu, ale ostatecznie możesz dostarczyć produkt w zaskakująco krótkim czasie programowania (im wcześniej naprawisz błąd, tym niższy koszt). A ponadto: jeśli w kodzie jest jakiś błąd, to go wykryjesz. Nie ma sposobu, aby błąd prześlizgnął się i spowodował problemy później.
To wciąż nie jest gwarancją kodu wolnego od błędów, ale jest o wiele bliżej niż zwykłe programy.
new IllegalArgumentException
wiadomość z? To znaczy, oprócz dodawania o throws
do deklaracji metody i kodu do zarządzania tym wyjątkiem w innym miejscu. Dlaczego assert
insetad rzucania nowy wyjątek? A może if
zamiast assert
? Naprawdę nie mogę tego dostać :(
a
może być negatywne. Drugie twierdzenie jest bezużyteczne; dla wartości int zawsze jest tak, że a + b - b == a. Ten test może się nie powieść tylko wtedy, gdy komputer jest zasadniczo uszkodzony. Aby bronić się przed tą nieprzewidzianą sytuacją, musisz sprawdzić spójność na wielu procesorach.
Asercje to narzędzie w fazie programowania do wychwytywania błędów w kodzie. Zostały zaprojektowane z myślą o łatwym usuwaniu, więc nie będą istnieć w kodzie produkcyjnym. A zatem twierdzenia nie są częścią „rozwiązania”, które dostarczasz klientowi. Są to kontrole wewnętrzne, aby upewnić się, że przyjęte założenia są prawidłowe. Najczęstszym przykładem jest testowanie na zero. Wiele metod zapisano w ten sposób:
void doSomething(Widget widget) {
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
Bardzo często w takiej metodzie widżet po prostu nigdy nie powinien mieć wartości zerowej. Jeśli więc ma wartość zero, w kodzie jest jakiś błąd, który należy wyśledzić. Ale powyższy kod nigdy tego nie powie. Więc w dobrej intencji pisania „bezpiecznego” kodu ukrywasz również błąd. O wiele lepiej jest napisać taki kod:
/**
* @param Widget widget Should never be null
*/
void doSomething(Widget widget) {
assert widget != null;
widget.someMethod(); // ...
... // do more stuff with this widget
}
W ten sposób z pewnością złapiesz ten błąd wcześniej. (Przydatne jest również określenie w umowie, że ten parametr nigdy nie powinien mieć wartości zerowej). Pamiętaj, aby włączyć asercje podczas testowania kodu podczas programowania. (Przekonanie do tego kolegów również jest często trudne, co jest dla mnie bardzo denerwujące).
Teraz niektórzy z twoich kolegów sprzeciwiają się temu kodowi, argumentując, że powinieneś nadal sprawdzać wartość zerową, aby uniknąć wyjątku w produkcji. W takim przypadku twierdzenie jest nadal przydatne. Możesz to napisać w ten sposób:
void doSomething(Widget widget) {
assert widget != null;
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
W ten sposób Twoi koledzy będą zadowoleni, że istnieje kod zerowy dla kodu produkcyjnego, ale podczas programowania nie ukrywasz już błędu, gdy widget jest zerowy.
Oto przykład z realnego świata: Kiedyś napisałem metodę, która porównała dwie arbitralne wartości równości, przy czym każda z nich może być zerowa:
/**
* Compare two values using equals(), after checking for null.
* @param thisValue (may be null)
* @param otherValue (may be null)
* @return True if they are both null or if equals() returns true
*/
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = thisValue.equals(otherValue);
}
return result;
}
Ten kod deleguje działanie equals()
metody w przypadku, gdy thisValue nie ma wartości null. Zakłada jednak, że equals()
metoda poprawnie wypełnia kontrakt equals()
, odpowiednio obsługując parametr zerowy.
Kolega sprzeciwił się mojemu kodowi, mówiąc mi, że wiele naszych klas ma błędne equals()
metody, które nie sprawdzają wartości zerowej, więc powinienem sprawdzić tę metodę. Jest to dyskusyjne, jeśli jest to rozsądne lub powinniśmy wymusić błąd, abyśmy mogli go wykryć i naprawić, ale odroczyłem się do mojego kolegi i sprawdziłem zerowo, co zaznaczyłem komentarzem:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = otherValue != null && thisValue.equals(otherValue); // questionable null check
}
return result;
}
Dodatkowe sprawdzenie tutaj other != null
jest konieczne tylko wtedy, gdy equals()
metoda nie sprawdza, czy wartość null jest wymagana w umowie.
Zamiast angażować się w bezowocną debatę z moim kolegą na temat mądrości pozwalającej błędnemu kodowi pozostać w naszej bazie kodu, po prostu umieszczam w nim dwa stwierdzenia. Te twierdzenia dadzą mi znać, na etapie programowania, jeśli jedna z naszych klas nie zaimplementuje się equals()
poprawnie, więc mogę to naprawić:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
assert otherValue == null || otherValue.equals(null) == false;
} else {
result = otherValue != null && thisValue.equals(otherValue);
assert thisValue.equals(null) == false;
}
return result;
}
Należy pamiętać o następujących kwestiach:
Asercje są tylko narzędziami w fazie rozwoju.
Istotą tego stwierdzenia jest powiadomienie użytkownika, jeśli wystąpi błąd, nie tylko w kodzie, ale w bazie kodu . (Asercje tutaj będą oznaczać błędy w innych klasach).
Nawet jeśli mój kolega był przekonany, że nasze zajęcia zostały poprawnie napisane, stwierdzenia tutaj nadal byłyby przydatne. Zostaną dodane nowe klasy, które mogą nie przetestować pod kątem wartości NULL, a ta metoda może oznaczać te błędy za nas.
Podczas programowania zawsze powinieneś włączać asercje, nawet jeśli napisany kod nie używa asercji. Moje IDE jest ustawione tak, aby zawsze domyślnie robiło to dla każdego nowego pliku wykonywalnego.
Asercje nie zmieniają zachowania kodu w środowisku produkcyjnym, więc mój kolega jest szczęśliwy, że istnieje kontrola zerowa i że ta metoda wykona się poprawnie, nawet jeśli equals()
metoda jest błędna. Cieszę się, bo złapię jakąkolwiek błędną equals()
metodę w fazie rozwoju.
Powinieneś również przetestować swoje zasady asercji, wprowadzając tymczasowe potwierdzenie, które się nie powiedzie, dzięki czemu będziesz mieć pewność, że otrzymasz powiadomienie za pośrednictwem pliku dziennika lub śledzenia stosu w strumieniu wyjściowym.
Wiele dobrych odpowiedzi wyjaśniających, na czym assert
polega słowo kluczowe, ale niewiele osób odpowiada na prawdziwe pytanie: „kiedy należy assert
używać słowa kluczowego w prawdziwym życiu?”
Odpowiedź: prawie nigdy .
Twierdzenia, jako koncepcja, są cudowne. Dobry kod ma wiele if (...) throw ...
instrukcji (i ich krewnych, takich jak Objects.requireNonNull
iMath.addExact
). Jednak niektóre decyzje projektowe znacznie ograniczyły użyteczność samego assert
słowa kluczowego .
Ideą przewodnią tego assert
słowa kluczowego jest przedwczesna optymalizacja, a główną funkcją jest łatwe wyłączenie wszystkich kontroli. W rzeczywistości assert
kontrole są domyślnie wyłączone.
Jednak niezwykle ważne jest, aby nadal przeprowadzano kontrole niezmiennicze w produkcji. Wynika to z faktu, że doskonałe pokrycie testowe jest niemożliwe, a cały kod produkcyjny będzie zawierał błędy, których stwierdzenia powinny pomóc w zdiagnozowaniu i złagodzeniu.
Dlatego if (...) throw ...
należy preferować użycie , podobnie jak jest to wymagane do sprawdzania wartości parametrów metod publicznych i do rzucania IllegalArgumentException
.
Czasami można pokusić się o napisanie niezmiennego czeku, którego przetworzenie zajmuje niepożądanie dużo czasu (i jest często wywoływane, aby miało znaczenie). Jednak takie kontrole spowolnią testowanie, co również jest niepożądane. Takie czasochłonne kontrole są zwykle zapisywane jako testy jednostkowe. Niemniej jednak czasami warto używać assert
tego powodu.
Nie używaj assert
po prostu dlatego, że jest czystszy i ładniejszy niż if (...) throw ...
(i mówię to z wielkim bólem, ponieważ lubię czyste i ładne). Jeśli po prostu nie możesz sobie pomóc i możesz kontrolować sposób uruchamiania aplikacji, możesz swobodnie korzystać, assert
ale zawsze włączaj asercje w środowisku produkcyjnym. Trzeba przyznać, że tak właśnie robię. Jestem naciska na adnotacji lombok że spowoduje assert
działać bardziej jak if (...) throw ...
. Głosuj na to tutaj.
(Rant: deweloperzy JVM byli bandą okropnych, przedwcześnie optymalizujących programistów. Dlatego słyszysz o tylu problemach bezpieczeństwa we wtyczce Java i JVM. Odmówili włączenia podstawowych kontroli i asercji w kodzie produkcyjnym, a my nadal kontynuujemy zapłacić cene.)
catch (Throwable t)
. Nie ma powodu, aby nie próbować łapać w pułapkę, rejestrować lub próbować / odzyskiwać z OutOfMemoryError, AssertionError itp.
assert
słowa kluczowego jest złe. Zmienię swoją odpowiedź, aby wyjaśnić, że mam na myśli słowo kluczowe, a nie pojęcie.
Oto najczęstszy przypadek użycia. Załóżmy, że włączasz wartość wyliczania:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
}
Tak długo, jak załatwisz każdą sprawę, nic ci nie będzie. Ale pewnego dnia ktoś doda figę do twojego wyliczenia i zapomni dodać go do instrukcji switch. Powoduje to błąd, który może być trudny do złapania, ponieważ efekty nie będą odczuwalne, dopóki nie opuścisz instrukcji switch. Ale jeśli napiszesz swój przełącznik w ten sposób, możesz go natychmiast złapać:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
default:
assert false : "Missing enum value: " + fruit;
}
AssertionError
jeśli asercje są włączone ( -ea
). Jakie jest pożądane zachowanie w produkcji? Cichy brak operacji i potencjalna katastrofa na późniejszym etapie egzekucji? Prawdopodobnie nie. Sugerowałbym wyraźne throw new AssertionError("Missing enum value: " + fruit);
.
default
aby kompilator ostrzegał Cię o brakujących przypadkach. Możesz return
zamiast tego break
(może to wymagać wyodrębnienia metody), a następnie obsłużyć brakującą literę po przełączeniu. W ten sposób otrzymujesz zarówno ostrzeżenie, jak i okazję assert
.
Asercje służą do sprawdzania warunków wstępnych i warunki wstępne „nigdy nie powinny zawieść”. Prawidłowy kod nigdy nie powinien zawieść twierdzenia; po uruchomieniu powinny wskazać błąd (mam nadzieję, że w miejscu, które jest blisko miejsca, w którym znajduje się faktyczne miejsce problemu).
Przykładem takiego stwierdzenia może być sprawdzenie, czy określona grupa metod jest wywoływana we właściwej kolejności (np. Która hasNext()
jest wywoływana wcześniej next()
w an Iterator
).
Do czego służy słowo kluczowe assert w Javie?
Spójrzmy na skompilowany kod bajtowy.
Dochodzimy do wniosku, że:
public class Assert {
public static void main(String[] args) {
assert System.currentTimeMillis() == 0L;
}
}
generuje prawie taki sam kod bajtowy jak:
public class Assert {
static final boolean $assertionsDisabled =
!Assert.class.desiredAssertionStatus();
public static void main(String[] args) {
if (!$assertionsDisabled) {
if (System.currentTimeMillis() != 0L) {
throw new AssertionError();
}
}
}
}
gdzie Assert.class.desiredAssertionStatus()
jest true
kiedy-ea
jest przekazywany w wierszu poleceń, a false w przeciwnym razie.
Używamy, System.currentTimeMillis()
aby upewnić się, że nie zostanie zoptymalizowany ( assert true;
zrobił).
Pole syntetyczne jest generowane tak, że Java musi wywoływać Assert.class.desiredAssertionStatus()
tylko raz w czasie ładowania, a następnie buforuje tam wynik. Zobacz także: Co oznacza „syntetyczny materiał statyczny”?
Możemy to sprawdzić za pomocą:
javac Assert.java
javap -c -constants -private -verbose Assert.class
W Oracle JDK 1.8.0_45 wygenerowano syntetyczne pole statyczne (patrz także: Co to znaczy „statyczny syntetyczny”? ):
static final boolean $assertionsDisabled;
descriptor: Z
flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
wraz ze statycznym inicjatorem:
0: ldc #6 // class Assert
2: invokevirtual #7 // Method java/lang Class.desiredAssertionStatus:()Z
5: ifne 12
8: iconst_1
9: goto 13
12: iconst_0
13: putstatic #2 // Field $assertionsDisabled:Z
16: return
a główną metodą jest:
0: getstatic #2 // Field $assertionsDisabled:Z
3: ifne 22
6: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
9: lconst_0
10: lcmp
11: ifeq 22
14: new #4 // class java/lang/AssertionError
17: dup
18: invokespecial #5 // Method java/lang/AssertionError."<init>":()V
21: athrow
22: return
Stwierdzamy, że:
assert
: jest to koncepcja języka Javaassert
mogłyby być naśladowane całkiem dobrze z właściwości systemu -Pcom.me.assert=true
, aby zastąpić -ea
w linii poleceń, a throw new AssertionError()
.catch (Throwable t)
klauzula jest w stanie wychwycić również naruszenia twierdzeń? Dla mnie ogranicza to ich użyteczność tylko do przypadku, gdy treść twierdzenia jest czasochłonna, co jest rzadkością.
AssertionError
pierwszy i ponownie go rzucić.
Przykład ze świata rzeczywistego, z klasy stosu (z twierdzeń w artykułach Java )
public int pop() {
// precondition
assert !isEmpty() : "Stack is empty";
return stack[--num];
}
Asercja pozwala wykryć defekty w kodzie. Możesz włączyć asercje do testowania i debugowania, pozostawiając je wyłączone, gdy program jest w produkcji.
Po co coś potwierdzać, skoro wiesz, że to prawda? Jest to prawdą tylko wtedy, gdy wszystko działa poprawnie. Jeśli program ma wadę, może nie być prawdą. Wykrywanie tego na wcześniejszym etapie pozwala stwierdzić, że coś jest nie tak.
assert
Oświadczenie zawiera to oświadczenie wraz z opcjonalnym String
wiadomości.
Składnia instrukcji assert ma dwie formy:
assert boolean_expression;
assert boolean_expression: error_message;
Oto kilka podstawowych zasad, które określają, gdzie należy stosować twierdzenia, a gdzie nie. Asercje należy stosować do:
Sprawdzanie poprawności parametrów wejściowych metody prywatnej. NIE dla metod publicznych. public
metody powinny generować regularne wyjątki, gdy zostaną przekazane złe parametry.
W dowolnym miejscu w programie, aby zapewnić ważność faktu, który prawie na pewno jest prawdziwy.
Na przykład, jeśli masz pewność, że będzie to tylko 1 lub 2, możesz zastosować takie twierdzenie:
...
if (i == 1) {
...
}
else if (i == 2) {
...
} else {
assert false : "cannot happen. i is " + i;
}
...
Asercji nie należy stosować do:
Sprawdzanie poprawności parametrów wejściowych metody publicznej. Ponieważ twierdzenia nie zawsze mogą być wykonywane, należy zastosować mechanizm regularnych wyjątków.
Sprawdzanie poprawności ograniczeń wprowadzanych przez użytkownika. Tak samo jak powyżej.
Nie powinien być stosowany w przypadku działań niepożądanych.
Na przykład nie jest to właściwe zastosowanie, ponieważ w tym przypadku twierdzenie jest używane ze względu na efekt uboczny wywołania doSomething()
metody.
public boolean doSomething() {
...
}
public void someMethod() {
assert doSomething();
}
Jedynym przypadkiem, w którym można to uzasadnić, jest próba ustalenia, czy asercje są włączone w kodzie:
boolean enabled = false;
assert enabled = true;
if (enabled) {
System.out.println("Assertions are enabled");
} else {
System.out.println("Assertions are disabled");
}
Oprócz wszystkich wspaniałych odpowiedzi tutaj podanych, oficjalny przewodnik po programowaniu Java SE 7 zawiera dość zwięzłą instrukcję obsługi assert
; z kilkoma przykładowymi przykładami, kiedy dobrym (i, co ważniejsze, złym) pomysłem jest używanie asercji, i czym różni się od zgłaszania wyjątków.
Assert jest bardzo przydatny podczas programowania. Używasz go, gdy coś po prostu nie może wydarzyć, jeśli Twój kod działa poprawnie. Jest łatwy w użyciu i może pozostać w kodzie na zawsze, ponieważ zostanie wyłączony w prawdziwym życiu.
Jeśli istnieje jakakolwiek szansa, że stan ten może wystąpić w prawdziwym życiu, musisz sobie z tym poradzić.
Uwielbiam to, ale nie wiem, jak go włączyć w Eclipse / Android / ADT. Wydaje się, że jest wyłączony nawet podczas debugowania. (Jest w tym wątek, ale odnosi się do „Java vm”, który nie pojawia się w konfiguracji uruchamiania ADT).
Oto stwierdzenie, które napisałem na serwerze dla projektu Hibernacja / SQL. Komponent bean miał dwie właściwości typu boolean, o nazwie isActive i isDefault. Każdy może mieć wartość „Y” lub „N” lub null, co zostało potraktowane jako „N”. Chcemy mieć pewność, że klient przeglądarki jest ograniczony do tych trzech wartości. Tak więc w moich ustawieniach dla tych dwóch właściwości dodałem to stwierdzenie:
assert new HashSet<String>(Arrays.asList("Y", "N", null)).contains(value) : value;
Zwróć uwagę na następujące kwestie.
To twierdzenie dotyczy tylko fazy rozwoju. Jeśli klient wyśle złą wartość, złapiemy to wcześnie i naprawimy na długo przed osiągnięciem produkcji. Twierdzenia dotyczą wad, które można wcześnie wykryć.
To twierdzenie jest powolne i nieefektywne. W porządku Asercje mogą być wolne. Nie obchodzi nas to, ponieważ są to narzędzia przeznaczone tylko do programowania. Nie spowolni to kodu produkcyjnego, ponieważ asercje zostaną wyłączone. (W tej kwestii jest trochę nieporozumień, do których dojdę później.) To prowadzi do mojego następnego punktu.
To twierdzenie nie ma skutków ubocznych. Mógłbym przetestować swoją wartość w stosunku do niezmodyfikowanego statycznego zestawu końcowego, ale ten zestaw pozostałby w produkcji, gdzie nigdy by się nie wykorzystał.
To twierdzenie istnieje, aby zweryfikować poprawne działanie klienta. Zanim dotrzemy do produkcji, będziemy mieć pewność, że klient działa poprawnie, dzięki czemu możemy bezpiecznie wyłączyć potwierdzenie.
Niektóre osoby pytają: jeśli twierdzenie nie jest potrzebne w produkcji, dlaczego nie po prostu je wyjąć, gdy skończysz? Ponieważ nadal będziesz ich potrzebować, gdy zaczniesz pracę nad kolejną wersją.
Niektórzy twierdzą, że nigdy nie powinieneś używać twierdzeń, ponieważ nigdy nie możesz być pewien, że wszystkie błędy zniknęły, więc musisz je zachować, nawet podczas produkcji. Dlatego nie ma sensu używać instrukcji assert, ponieważ jedyną zaletą stwierdzeń jest to, że można je wyłączyć. Dlatego, zgodnie z tym tokiem myślenia, nie powinieneś (prawie) nigdy używać twierdzeń. Nie zgadzam się. Z pewnością prawdą jest, że jeśli test należy do produkcji, nie powinieneś używać twierdzenia. Ale ten test nie należy do produkcji. Ten służy do wychwytywania błędu, który prawdopodobnie nigdy nie osiągnie produkcji, więc można go bezpiecznie wyłączyć, gdy skończysz.
BTW, mogłem napisać tak:
assert value == null || value.equals("Y") || value.equals("N") : value;
Jest to w porządku tylko dla trzech wartości, ale jeśli liczba możliwych wartości rośnie, wersja HashSet staje się wygodniejsza. Wybrałem wersję HashSet, aby zwrócić uwagę na wydajność.
HashSet
przynosi jakąkolwiek przewagę prędkości nad ArrayList
. Co więcej, zestaw i lista dominują w czasie wyszukiwania. Przydałyby się przy użyciu stałej. To wszystko powiedział +1.
Asercja jest zasadniczo używana do debugowania aplikacji lub jest używana w zamian za obsługę wyjątków dla niektórych aplikacji w celu sprawdzenia ważności aplikacji.
Asercja działa w czasie wykonywania. Prosty przykład, który może wyjaśnić całą koncepcję w prosty sposób, znajduje się tutaj - Co robi słowo kluczowe assert w Javie? (WikiAnswers).
Asercje są domyślnie wyłączone. Aby je włączyć, musimy uruchomić program z -ea
opcjami (szczegółowość można zmieniać). Na przykład java -ea AssertionsDemo
.
Istnieją dwa formaty korzystania z asercji:
assert 1==2; // This will raise an AssertionError
.assert 1==2: "no way.. 1 is not equal to 2";
podniesie błąd AssertionError z wyświetlonym komunikatem, a zatem jest lepszy. Chociaż w rzeczywistej składni assert expr1:expr2
wyrażeniem2 może być dowolne wyrażenie zwracające wartość, używałem go częściej tylko do drukowania wiadomości.Podsumowując (dotyczy to wielu języków, nie tylko Java):
„assert” jest przede wszystkim używany przez programistów jako pomoc przy debugowaniu podczas procesu debugowania. Komunikaty assert nigdy nie powinny się pojawiać. Wiele języków udostępnia opcję czasu kompilacji, która spowoduje, że wszystkie „twierdzenia” zostaną zignorowane, do użycia przy generowaniu kodu „produkcyjnego”.
„wyjątki” są wygodnym sposobem radzenia sobie z wszelkimi rodzajami błędów, niezależnie od tego, czy reprezentują one błędy logiczne, ponieważ jeśli napotkasz taki błąd, że nie możesz kontynuować, możesz po prostu „wyrzucić je w powietrze, „gdziekolwiek jesteś, oczekując, że ktoś będzie gotowy„ złapać ”ich. Kontrola jest przekazywana w jednym kroku, prosto z kodu, który wyrzucił wyjątek, prosto do rękawicy łapacza. (I łapacz może zobaczyć pełny ślad połączeń, które miały miejsce.)
Co więcej, osoby dzwoniące z tego podprogramu nie muszą sprawdzać, czy podprogram się powiódł: „jeśli już tu jesteśmy, to musiałby się udać, ponieważ w przeciwnym razie wygenerowałby wyjątek i nie byłoby nas tutaj!”Ta prosta strategia znacznie ułatwia projektowanie i debugowanie kodu.
Wyjątki dogodnie pozwalają, aby warunki błędu krytycznego były takimi, jakimi są: „wyjątki od reguły”. I dla nich będzie obsługiwana przez ścieżkę kodu, która jest również „wyjątkiem od reguły… ” fly ball! ”
Asercje to kontrole, które mogą zostać wyłączone. Są rzadko używane. Dlaczego?
result != null
ponieważ takie kontrole są bardzo szybkie i nie ma prawie nic do zapisania.Co zostało? Drogie sprawdza warunkach naprawdę oczekiwać , aby mogło być prawdziwe. Dobrym przykładem mogą być niezmienniki struktury danych, takie jak drzewo RB. W rzeczywistości w ConcurrentHashMap
JDK8 istnieje kilka takich znaczących twierdzeń dotyczących TreeNodes
.
Czasami czek nie jest naprawdę drogi, ale jednocześnie jesteś pewien, że minie. W moim kodzie jest np.
assert Sets.newHashSet(userIds).size() == userIds.size();
gdzie jestem całkiem pewien, że właśnie utworzona lista zawiera unikalne elementy, ale chciałem ją udokumentować i dokładnie sprawdzić.
Zasadniczo „potwierdź prawda” przejdzie, a „potwierdź fałsz” nie powiedzie się. Zobaczmy, jak to będzie działać:
public static void main(String[] args)
{
String s1 = "Hello";
assert checkInteger(s1);
}
private static boolean checkInteger(String s)
{
try {
Integer.parseInt(s);
return true;
}
catch(Exception e)
{
return false;
}
}
assert
jest słowem kluczowym. Został wprowadzony w JDK 1.4. Istnieją dwa rodzaje assert
s
assert
stwierdzeniaassert
instrukcje.Domyślnie wszystkie assert
instrukcje nie zostaną wykonane. Jeśli assert
instrukcja otrzyma wartość false, wówczas automatycznie zgłosi błąd asercji.