Cześć, zgodnie z planem zapraszam na pierwsze spotkanie przygotowujące nas do SCJP. Poruszana tematyka to: Flow Control, Exceptions, Assertions Najpierw zobaczymy na co szczególnie kładą nacisk materiały do SCJP, a następnie pobawimy się z zadaniami i zagadkami. Zapowiada się niezła zabawa
hej, nieobecnym opiszę po krótce jak nam się udało pierwsze spotkanie. Przejrzenie rozdziału "Flow Control, Exceptions, Assertions" zajęło mi ok 1,5 godziny. Na spotkaniu zajęło nam prawie godzinę przewertowanie go jeszcze raz, skupiając się tylko na ciekawych rzeczach, a było na czym :-)
Za książką: "Don't get your hopes up about the exam questions being all nice and indented properly [...] anything that can be made more confusing, will be." Dalej w wielu miejscach ostrzegają, by uważnie sprawdzić czy kod w zadaniu się w ogóle skompiluje, a dopiero następnie analyzować treść zadania. Wielokrotnie jedną z odpowiedzi jest "This code won't compile".
1. Konstrukcja "if": - uważać na wielokrotnie zagnieżdżone if'y, oraz który else jest do którego if'a. Na ogół proste, robi się trudniejsze gdy kod jest nie wcięty albo podstępnie źle sformatowany. - uważać na przypisania w miejscu instrukcji warunkowej. Jeśli przypisanie jest typu boolean, to się skompiluje; w innych przypadkach nie.
2. Konstrukcja "switch" - uwaga na typ wyrażenia w instrukcji warunkowej. Może być tylko char, byte, short, int, enum. Nie long - ciekawy kwiatek: (nie skompiluje się, gdyż 128 jest spoza zakresu byte) byte i = 0; switch (i) { case 128: ...
}
- uwaga na celowo błędne konstrukcje, np. pomijające słowo kluczowe case, lub dwukropki
switch (x) { case 0 { }
}
switch (x) { 0: { ... } 1: { ... }
}
- uważać by nie przegapić opcji "default"
3. Pętle i iteratory - uwaga na niepoprawne konstrukcje, np. while (int x = 2) {...} - for-each: typ zmiennej pętli musi się zgadzać z typem obiektu po którym iterujemy - continue/break: muszą być wewnątrz pętli lub w switch (to się nie odnosi do podpisanych breaków/labeled break) - prosty kawałek kodu na przemyślenie:
boolean isTrue = true; outer: for (int i=0; i<5;i++) { while (isTrue) { System.out.println("Hello"); break outer; } // end of inner while loop System.out.println("Outer loop."); // won't print
} // end of outer for loop
Syste.out.println("Good-Bye");
Prints: Hello Good-Bye
outer: for (int i=0; i<5;i++) { while (isTrue) { System.out.println("Hello"); continue outer; } // end of inner while loop System.out.println("Outer loop."); // won't print
} // end of outer for loop
Syste.out.println("Good-Bye");
Prints: Hello Hello Hello Hello Hello Good-Bye
4. Wyjątki - znać hierarchię typów Throwable, Error, Exception, RuntimeException - znać kilka podstawowych typów wyjątków i umieć ocenić czy w podanym kodzie zostaną wyrzucone: ArrayIndexOutOfBounds, ClassCastException, IllegalArgumentException, NullPointerException, NumberFormatException, AssertionError, ExceptionInInitializerError, StackOverflowError, NoClassDefFoundError - część z powyższych jest typowo wyrzucana tylko przez JVM a część przez programistę. umieć rozróżnić - uważać na celowe błędy w konstrukcji ty/catch/finally, np. bezsensowne instrukcje wstrzelone gdzieś między klauzulami - uwaga na kolejność deklarowania wyjątków w sekcjach catch: od bardziej szczegółowych do bardziej ogólnych, łatwo tu o błędy kompilatora - umieć prześledzić czy sprawdzany wyjątek (checked exception) jest poprawnie obsłużony, np. w zadaniu z łańcuchem wywołań funkcji - wiedzieć co się stanie jeśli nieobsłużony wyjątek zostanie wyrzucony w głównej metodzie programu - ciekawy przykład jednej z osób z sali: int doSth() { try { return 10;
} finally { return 20; } }
5. Asercje - budowa asercji: assert(wyrazenieWarunkowe):wyrazenie2 - :wyrazenie2 jest opcjonalne i zostanie doklejone do wyjątku w przypadku nie spełnienia asercji, np. assert(i >= 10):"i is less than 10"; - assert a różne wersje javy. Od javy 1.4, assert jest słowem kluczowym i użycie np. jako nazwa zmiennej kończy się błędem kompilacji - włączanie/wyłączanie asercji: -ea, -enableassertions, -da, -disableassertions, -dsa (assertions for system library) - selektywne włączanie/wyłączanie asercji: -ea:com.package.Foo (włączenie tylko dla klasy Foo), -ea:com.package... (dla pakietu package i jego podpakietów) - nie używać asercji w metodach publicznych
Na końcu rozdziału jest przydatny 2-minute drill krótka ściąga z mniej więcej wszystkim co powyżej.
Następnie 15 zadań. Wcześniej szacowaliśmy po 30sec-1min na zadanie. Okazuje się że dobrze mieć do 4-5min na zadanie, na ogół trzeba dokładnie przeanalizować każdą opcję, np. wstawić każdą odpowiedź do przykładowego kawałku kodu i ocenić czy się skompiluje, lub przeanalizować każde ze zdań czy jest poprawne/nie. Często są też zadania typu "co wypisze dany program"...
Zdąrzyliśmy zrobić 5 zadań :-)
mam nadzieję że wszyscy się dobrze bawili. Moje wrażenie jest takie że do egzamu najlepiej podchodzić już z odrobiną doświadczenia w czytaniu i rozumieniu kodu. Niestety egzamin nie kładzie nacisku na typowe błędy programistyczne, a bardziej na znajomość działania kompilatora i wykrywanie problemów którymi w większości obecnie zajmują się IDE. ...chociaż może to dlatego że temat tego rozdziału nie był zbyt wysublimowany i tam się nie da popełnić większych błędów a zadania i tak muszą pokrywać cały materiał :-P
Następne spotkanie w następny poniedziałek. Szczegóły już w krótce! Zapraszam!
Jacek
2009/9/20 Jacek Pospychała <jacek.pospych...@gmail.com>
> Cześć, > zgodnie z planem zapraszam na pierwsze spotkanie przygotowujące nas do > SCJP. > Poruszana tematyka to: Flow Control, Exceptions, Assertions > Najpierw zobaczymy na co szczególnie kładą nacisk materiały do SCJP, a > następnie > pobawimy się z zadaniami i zagadkami. > Zapowiada się niezła zabawa
> 1. Konstrukcja "if": > ... > - uważać na przypisania w miejscu instrukcji warunkowej. Jeśli przypisanie > jest typu boolean, to się skompiluje; w innych przypadkach nie.
Oczywiście konstrukcje if / while mogą zawierać przypisania inne niż boolean, o ile całe wyrażenie będzie typu boolean, np.: if ((a=5) > 0) { ... }
Tak moim skromnym zdaniem, egzamin skupia się za bardzo na poprawności syntaktycznej - innymi słowy wcielamy się w kompilator, musząc zwracać uwagę np. na to, czy nie zapomniano dwukropka za etykietą case. Mały ma to związek z byciem "dobrym" programistom, czy nawet wydajnym programistą (kompilator javac - w przeciwieństwie np. do g++ - sam wyłapie nam każdy brakujący średnik). Wyobraża sobie ktoś wrzucić niepoprawny składniowo kod do repozytorium? Imo egzamin powinien skupiać się bardziej na błędach logicznych / wynikających z braku znajomości dokumentacji.
Niestety tak jest. Ma to pewne walory -- programista uważny patrzy na
to, co pisze, a nie tylko korzysta z pomocy kompilatora. Ja sam
spotkałem się parę razy w życiu z przypadkowymi błędami, których
kompilator nie wyłapie, bo są poprawne składniowo, lecz łudząco dobre:
float var = 0.4;
if (var > 0.5); {
System.out.println("var > 0.5");
}
Jak się człowiek skupi, to widać gdzie jest problem, ale taki kod się
normalnie kompiluje. Sam jednak również jestem przeciwny łapaniu na
tego typu konstrukcje, bo to nigdzie nie prowadzi.
>> 1. Konstrukcja "if":
>> ...
>> - uważać na przypisania w miejscu instrukcji warunkowej. Jeśli przypisanie
>> jest typu boolean, to się skompiluje; w innych przypadkach nie.
> Oczywiście konstrukcje if / while mogą zawierać przypisania inne niż
> boolean, o ile całe wyrażenie będzie typu boolean, np.:
> if ((a=5) > 0) { ... }
> Tak moim skromnym zdaniem, egzamin skupia się za bardzo na poprawności
> syntaktycznej - innymi słowy wcielamy się w kompilator, musząc zwracać
> uwagę np. na to, czy nie zapomniano dwukropka za etykietą case. Mały
> ma to związek z byciem "dobrym" programistom, czy nawet wydajnym
> programistą (kompilator javac - w przeciwieństwie np. do g++ - sam
> wyłapie nam każdy brakujący średnik). Wyobraża sobie ktoś wrzucić
> niepoprawny składniowo kod do repozytorium? Imo egzamin powinien
> skupiać się bardziej na błędach logicznych / wynikających z braku
> znajomości dokumentacji.
> Niestety tak jest. Ma to pewne walory -- programista uważny patrzy na > to, co pisze, a nie tylko korzysta z pomocy kompilatora. Ja sam > spotkałem się parę razy w życiu z przypadkowymi błędami, których > kompilator nie wyłapie, bo są poprawne składniowo, lecz łudząco dobre:
> float var = 0.4; > if (var > 0.5); { > System.out.println("var > 0.5"); > }
> Jak się człowiek skupi, to widać gdzie jest problem, ale taki kod się > normalnie kompiluje. Sam jednak również jestem przeciwny łapaniu na > tego typu konstrukcje, bo to nigdzie nie prowadzi.
Mały wtręt ze światka .NET: javac nie wygeneruje ostrzeżenia w takiej sytuacji?
W dniu 22 września 2009 10:31 użytkownik Leszek Ciesielski <skol...@gmail.com> napisał:
> Mały wtręt ze światka .NET: javac nie wygeneruje ostrzeżenia w takiej sytuacji?
Ależ oczywiście, że wygeneruje... Wygeneruje "possible loss of precision", wszak w kodzie występuje próba przypisania wartości "0.4", która jest typu double na "węższy" typ float :-P
Pozdrawiam!
PS. no offfence - only kidding ;-)
-- yacoll
Optymiści wierzą, że świat stoi przed nimi otworem. Pesymiści wiedzą, gdzie ma ten otwór.
>> Niestety tak jest. Ma to pewne walory -- programista uważny patrzy na >> to, co pisze, a nie tylko korzysta z pomocy kompilatora. Ja sam >> spotkałem się parę razy w życiu z przypadkowymi błędami, których >> kompilator nie wyłapie, bo są poprawne składniowo, lecz łudząco dobre:
>> float var = 0.4; >> if (var > 0.5); { >> System.out.println("var > 0.5"); >> }
>> Jak się człowiek skupi, to widać gdzie jest problem, ale taki kod się >> normalnie kompiluje. Sam jednak również jestem przeciwny łapaniu na >> tego typu konstrukcje, bo to nigdzie nie prowadzi.
> Mały wtręt ze światka .NET: javac nie wygeneruje ostrzeżenia w takiej sytuacji?
Javac niestety nie, ale każde szanujące się IDE już tak.
2009/9/22 Jacek Pospychała <jacek.pospych...@gmail.com>
> to zależy... np. w Eclipse to jest domyślnie wyłączone, ale po włączeniu > (opcja "Empty statement" dla ciekawskich), owszem...
hehe, w załączniku pełna referencja różnych fajnych opcji... może zamiast przygotowywać się do SCJP zrobimy sobie spotkanie, pt. jak wyeliminować głupie błędy?
najprostszy sposób na rozpowszenienie tych opcji w zespole to skonfigurować opcje ostrzeżeń/błędów specyficznie dla projektu - wówczas ustawienia zostaną zapisane w plikach <project>\.settings, a następnie wrzucić całość z projektem do CVS/SVN/whatever.
Poza tym raz na jakiś czas warto jednak przejechać projekt FindBugs'em lub innym narzędziem do statycznej analizy kodu, naprawdę nie boli, a można się wiele ciekawych rzeczy dowiedzieć. Taki ciekawy przykład:
private void doSth(File file) { FileWriter writer; try { writer = new FileWriter(file); /* some magic here */ } catch (IOException e) { new RuntimeException(e); } finally { FileUtil.close(writer); } }
PS. Brat mnie uprzedził z FindBugsem gdy pisałem tego posta :)
> Poza tym raz na jakiś czas warto jednak przejechać projekt FindBugs'em > lub innym narzędziem do statycznej analizy kodu, naprawdę nie boli, a > można się wiele ciekawych rzeczy dowiedzieć. Taki ciekawy przykład:
Ośmielę się zapytać - co jest ciekawego w tym przykładzie, poza tym, że się on nie skompiluje? (w finally używana jest zmienna writer, która może być niezainicjalizowana - wykryje to kompilator, nie potrzeba FindBugs)
> W dniu 22 września 2009 11:00 użytkownik Marcin Kłopotek > <marcin.klopo...@gmail.com> napisał:
>> Poza tym raz na jakiś czas warto jednak przejechać projekt FindBugs'em >> lub innym narzędziem do statycznej analizy kodu, naprawdę nie boli, a >> można się wiele ciekawych rzeczy dowiedzieć. Taki ciekawy przykład:
> Ośmielę się zapytać - co jest ciekawego w tym przykładzie, poza tym, > że się on nie skompiluje? (w finally używana jest zmienna writer, > która może być niezainicjalizowana - wykryje to kompilator, nie > potrzeba FindBugs)
Braciszku, załóżmy że poprawiłeś błąd kompilacji. Mała podpowiedź, spójrz na blok catch {...} Finbugs jednak się przyda w tym przypadku, bo jak widać kompilator i Ty nie zauważaliście pomyłki ;)
> 2009/9/22 Artur Kłopotek <a.klopo...@gmail.com>:
>> W dniu 22 września 2009 11:00 użytkownik Marcin Kłopotek
>> <marcin.klopo...@gmail.com> napisał:
>>> Poza tym raz na jakiś czas warto jednak przejechać projekt FindBugs'em
>>> lub innym narzędziem do statycznej analizy kodu, naprawdę nie boli, a
>>> można się wiele ciekawych rzeczy dowiedzieć. Taki ciekawy przykład:
>> Ośmielę się zapytać - co jest ciekawego w tym przykładzie, poza tym,
>> że się on nie skompiluje? (w finally używana jest zmienna writer,
>> która może być niezainicjalizowana - wykryje to kompilator, nie
>> potrzeba FindBugs)
> Braciszku, załóżmy że poprawiłeś błąd kompilacji. Mała podpowiedź,
> spójrz na blok catch {...} Finbugs jednak się przyda w tym przypadku,
> bo jak widać kompilator i Ty nie zauważaliście pomyłki ;)
> Braciszku, załóżmy że poprawiłeś błąd kompilacji. Mała podpowiedź, > spójrz na blok catch {...} Finbugs jednak się przyda w tym przypadku, > bo jak widać kompilator i Ty nie zauważaliście pomyłki ;)
Napotkawszy błąd kompilacji, zaniechałem dalszej analizy ;-)
> Napotkawszy błąd kompilacji, zaniechałem dalszej analizy ;-)
Niestety te pytania SUNa mają podobny charakter -- często jest zasłona dymna, a błąd kryje się w innym miejscu. Ja zresztą nie neguję tego, że dużo błędów da się wyłapać automatycznie (findbugs, czy jdt); po prostu nie wszystkie się da, a czasem głupi błąd jest najtrudniejszy do znalezienia.
Dawid
P.S. Do Leszka: .NET, a w zasadzie C# ma nowszą specyfikację i parę rzeczy napisanych zostało dużo lepiej. Między innymi compound assignments typu +=, -= itd. są dużo ładniejsze i lepiej zdefiniowane. Java ciągnie się długo i wiele rzeczy narosło lub zostało nałożonych na kompilator (klasy wewnętrzne, syntetyczne accesory) lub jako nieco koślawe rozszerzenie (erasure w generykach).