Express killers, cz. I
Z przyjemnością witam w nowym cyklu Express killers. Dział będzie prezentował ciekawe (nie koniecznie zalecane!) przypadki użycia języka Java. Jestem zwolennikiem korzystania z IDE i wszystkich jego możliwości, które oferuje, dlatego problemy tutaj poruszane nie będą pytaniem, dlaczego poniższy kod się nie kompiluje?
public class Object { Object o = new Object() { public String toString() { return null; } } }
Nie będę także czytelników zanudzał pytaniami o wynik takiego wyrażenia:
int i = 0x12<<3+04^5>>06>>>7|8&9;
bo przecież po to są nawiasy, żeby sobie życie ułatwiać oraz internet, żeby nie trzeba było pamiętać, który operand będzie pierwszy brany do wyliczenia.
Co zatem będzie tematem? Najlepsze są przykłady z życia wzięte. Ot np. taki:
import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; public class Pool { private static Logger logger = Logger .getLogger(Pool.class.getName()); private Vectormessages; private Integer status; public boolean add(String message) { logger.log(Level.ALL, "addding:" + this); return messages.add(message); } public String get(int index) { logger.log(Level.ALL, "getting:" + this); return messages.get(index); } public String toString() { StringBuffer sb = new StringBuffer(); int i = 1; do { sb.append(get(i)).append(","); } while (++i < messages.size()); sb.append(status); return sb.toString(); } public static void main(String[] args) { Pool p = new Pool(); p.add("hello"); System.out.println(p.get(0)); } }
Biorąc pod uwagę, że powyższy kod się kompiluje, które z poniższych odpowiedzi dotyczą sytuacji po jego uruchomieniu?
- Uruchomienie zakończy się błędem
java.lang.ArrayIndexOutOfBoundsException
, gdyż w metodzie
toString()
nieprawidłowo inicjalizowana jest pętla.
- Gdyby zmienna status
była prymitywem, program nie
zakończyłby się wyjątkiem.
- Program zakończy się poprawnie, a na wyjście zostanie wypisany
napis hello
.
- Wyjątek java.lang.NullPointerException
zostanie rzucony
w pętli metody toString()
.
- Żadna z powyższych odpowiedzi nie jest prawidłowa.
Odpowiedź na to pytanie pozostawiamy czytelnikowi, który może uruchomić powyższy kod w swoim ulubionym środowisku programistycznym. Może także poszukać jej na kolejnych stronach Java exPress.
A oto i drugie zadanie. Jego specyfika nie przeszkadza, by wkleić następującą metodę do swojego IDE i sprawdzić, jak się zachowuje po uruchomieniu. Oto kawałek kodu pewnej klasy:
public static void main(String[] args) throws Exception { CatchNull test = new CatchNull(); if (test == null) { throw new NullPointerException("null object"); } if (!(test instanceof CatchNull)) { throw new UnknownError( "not an instanceof CatchNull"); } }
W jakim przypadku uruchomienie powyższego kodu spowoduje rzucenie jednego z dwóch wyjątków? Odpowiedź, podobnie, jak do poprzedniego pytania, na dalszych stronach. Gorąco także zachęcam do poszukania jej samemu!
Serdecznie zapraszam wszystkich, by pochwalili się z czytelnikami swoimi interesującymi kawałkami kodu. Najlepsze będą publikowane i nagradzane na łamach czasopisma. Mogą to być także kawałki kodu z cyklu WTF. Praca codziennie dostarcza interesujące przykłady, po przeczytaniu których programista zaczyna sprawdzać elementarne podstawy swojej wiedzy. Niech zaczną ją też sprawdzać inni za pośrednictwem Java exPress.
Odpowiedzi:
W pierwszym przykładzie w metodzie main(String[])
jest
wywołanie metody get(int)
co spowoduje zapisanie tej
informacji w logach. Użycie słowa kluczowego this
zakończy
się wywołaniem metody toString()
. W metodzie
toString()
następuje iteracja po wszystkich elementach
kolekcji. Chociaż pętla nie jest napisana poprawnie, to przy pierwszej
iteracji nie zostanie zgłoszony żaden wyjątek. Zostanie natomiast
wywołana metoda get(int)
. W konsekwencji wygenerowany
zostanie wyjątek o przepełnieniu stosu
java.lang.StackOverflowError
.
W drugim przypadku żaden wyjątek nie zostanie rzucony. Pierwszy z
nich byłby rzucony, gdyby zmienna test
nie została poprawnie
stworzona. Miałoby to miejsce, gdyby konstruktor rzucił wyjątek lub
gdyby maszyna wirtualna nie posiadała wystarczającej ilości pamięci do
stworzenia nowego obiektu. Gdyby tak się stało, to rzucony wyjątek nie
zostałby chwycony, a zatem pierwsza instrukcja warunkowa nie zostanie
wykonana. W takim przypadku także druga instrukcja warunkowa nie
zostanie sprawdzona.
Druga instrukcja warunkowa przy deklaracji zmiennej test
jako CatchNull
nie ma sensu. Kompilator (lub maszyna
wirtualna, jeśli zastosować rzutowanie) nie dopuści, aby do zmiennej
typu CatchNull
został przypisany obiekt, który nie jest
typem CatchNull
lub pochodnym. Jedynym przypadkiem, by
warunek drugi był prawdziwy jest, by zmienna test
była
równa null
, co według wcześniejszego wywodu nie jest możliwe.
Nobody has commented it yet.