Monthly Archives: August 2009

I znowu ciekawe zmiany w SCJP

Pisałem nie tak dawno o zmianach w ilości pytań egzaminacyjnych (tym samym progu zdania) dla SCJP w wersji 1.6. Co ciekawe dalszych zmian nie ma końca – w tym jednakże przypadku mogę powiedzieć z całą pewnością – jest lepiej.

Czego konkretnie dotyczą zmiany? Otóż rzecz w wykreśleniu z wymagań dla egzaminu trzech dość istotnych wymagań (no, może dwa są dość istotne):

“Develop code that declares both static and non-static methods, and – if appropriate – use method names that adhere to the JavaBeans naming standards. Also develop code that declares and uses a variable-length argument list.”

“Develop code that serializes and/or de-serializes objects using the following APIs from java.io: DataInputStream, DataOutputStream, FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream and Serializable.”

“Given a scenario, write code that makes appropriate use of wait, notify, or notifyAll.”

Czyli serializację i połowę potencjalnych pytań o wątki szlag trafił. Pewnie są to dość istotne zagadnienia (czy aby na pewno?) z punktu widzenia programisty Java, jednakże raczej nikt nie spodziewa się, iż po zdaniu SCJP nagle człowiek staje się guru programowania. Ja zatem jakoś specjalnie za nimi nie płaczę. Stosowny temat na JavaRanch można znaleźć pod tym adresem.

Best of the best z SCJP

Ostatnio sporo w tym temacie się u mnie dzieje (dlatego wpisy trochę przystopowały). Testowy egzamin robię średnio 2h i po przejrzeniu poprawnych odpowiedzi z definicji jestem tak skonany, że nic już mi się nie chce. Jednakże dziś taka mała gratka dla wszystkich programistów Javy – niezależnie czy przygotowują się do egzaminu czy nie – całkiem spora lista rzeczy, które zapisałem sobie podczas przerabiania testowych egzaminów, a które są dość podchwytliwe i mogą łatwo człowieka wywieść na manowce.

Listę będę starał się cały czas aktualizować. Jak już zdam ten nieszczęsny egzamin to pewnie powstanie kolejna strona na blogu poświęcona SCJP i tam pewnikiem umieszczę wszystkie materiały. Gdyby ktoś chciał dodać do tej listy jakiegoś “onelinera” to proszę o mejla lub komentarz.

  • w przypadku klas Boolean otrzymują one wartość TRUE tylko wówczas, jeśli przekazaną wartością do konstruktora jest “true” – niezależnie od wielkości liter. Wszystko inne (łącznie z NULL) daje FALSE.
  • w przypadku przekazywania do metod/klas pracujących nad tokenizacją tekstu jakichkolwiek wzorców należy pamiętać, że w klasie String należy używać 2 slashy by wprowadzić znak specjalny (np. “\\s”)
  • zsynchronizowane mogą być tylko metody oraz bloki kodu
  • uśpienie obecnie działającego wątku (za pomocą Thread.sleep()) z podaniem wartości czasowej (pamiętajmy – milisekundy) powoduje, że upłynie MINIMUM dany okres czasu zanim wątek ten powróci do gry. Może to być więcej, jeśli np. w tym czasie JVM przydzieli czas innym wątkom będącym na tym samym poziomie uprzywilejowania.
  • wątek kończy swe działanie wówczas, gdy kończy wykonywać się jego metoda run(). Tutaj warto zwrócić uwagę na to, że metoda start() klasy Thread wywołuje swą metodę run().
  • method inner-classes nie mogą korzystać ze zmiennych lokalnych, chyba że są one zadeklarowane jako final
  • skompilowanie programu z użyciem asercji to nie do końca to samo co uruchomienie programu z użyciem asercji
  • warto pamiętać o zasadach dotyczących nadpisywania i przeciążania metod. Zwłaszcza o tej, że metoda statyczna nie może być nadpisana przez niestatyczną i vice versa. Przeciążanie zaś polega na zmianie parametrów oraz na opcjonalnej zmianie zwracanego typu.
  • Unreachable statement to nie wyjątek tylko błąd czasu kompilacji!
  • porównywanie typów prostych z klasami opakowującymi za pomocą metody equals jest jak najbardziej OK. Autoboxing da sobie z tym radę.
  • dzielenie modulo działa dość prosto – zawsze zwraca wartość INT, a z kolei znak jest uzależniony od znaku lewego operandu
  • modyfikator abstract private jest możliwy tylko w przypadku klas wewnętrznych
  • poprzez instrukcje statycznego importu (import static) możemy zaimportować tylko stałe i metody
  • zmienne interfejsu są domyślnie stałę (public, static, final), zaś metody interfejsu są domyślnie public i abstract).
  • kiedy metoda nie zwraca wartości (typ void), wówczas można w ciele takiej metody czystej instrukcji return;. Kod taki się skompiluje i wszystko jest OK. Jeśli jednakże metoda deklaruje, że zwróci jakąś wartość, wówczas zwraca tą wartość lub NULL.
  • konstruktor klasy String tworzy nowy obiekt za każdym razem. Używanie do tworzenia łańcuchów przeciążonego operatora równości powoduje pierwej wyszukanie tworzonej wartości w istniejącej puli łańcuchów.
  • pamiętajmy o porówywaniu typów prostych z klasami opakowującymi i tych samych klas opakowujących. Dotyczy ten temat liczb z przedziału -128 do 127, a także wartości Boolean oraz Char (w pewnym przedziale).
  • przy metodach operujących na łańcuchach (StringBuilder też się łapie) pamiętajmy, że w metodach dwuargumentowych drugi parametr jest cyfrą, która licząc znaki od 0 jest pierwszą literą, która zostanie z istniejącego obiektu po dokonaniu danej operacji (np. metody substring czy delete).
  • klasa File posiada mało znane (w kotenkście egzaminu) metody canRead() oraz canWrite()), która wskazuje czy dany plik da się odczytać/zapisać.
  • metoda getInstance() z parametrem typu Locale istnieje tylko dla klas Calendar oraz NumberFormat.
  • zmienne zadeklarowane w blokach inicjalizacyjnych nie są dostępne poza nimi.
  • tablice można też tworzyć w ten sposób:
    int[] a = {1};
  • klasy anonimowe (anonymous inner-classes) nie mogą posiadać deklaracji statycznych
  • w przypadku typów wyliczeniowych należy pamiętać, iż wyszczególnienie elementów zbioru musi być pierwszą rzeczą w kodzie tworzącym typ wyliczeniowy.
  • naturalny porządek sortowania łańcuchów tekstowych to:
    • białe znaki
    • “krzaczki” (np. @)
    • cyfry
    • wielkie litery
    • małe litery
  • tablice mogą mieć rozmiar 0
  • liczby typu float oraz double można dzielić przez zero!!! Spowoduje to zwrócenie wartości “Inifinity”
  • dla przypomnienia – wynikiem działań matematycznych jest domyślnie wartość int
  • wywołanie System.gc() nie daje pewności, że GC w ogóle ruszy
  • wartości prymitywne w kolekcjach są sortowane z użyciem własnych zasad. Nie da się do nich zastosować klas implementujących Comparator.
  • przeszukiwanie tablic oraz kolekcji musi odbywać się za pomocą takiego samego Comparatora, co sortowanie.

Zmiany zasad dla SCJP

Anom. Postanowiłem sobie w końcu zakupić voucher na egzamin. Jest on ważny rok, zatem nie obliguje mnie do zapisywania się na egzamin w perspektywie najblizszego tygodnia. Grzecznie odwiedziłem stronę firmy Sun i dotarłem na odpowiednią stronkę. I zonk!

Było trochę późno (w sumie jak zawsze kiedy coś próbuję w javie zdziałać 🙂 i dlatego na początku pomyślałem, że coś pokiełbasiłem. No ale patrzę na oznaczenie 310-065, Sun Certified, itp – czyli wszystko ok. Natomiast piszą mi ni stąd, ni z owąd, iż egzamin ma 60 pytań i do jego zdania wystarcza coś koło 58%. WTF? Udałem się do mądrzejszych ode mnie, a tam odesłano mnie pod ten adres. No i faktycznie – zmiany są oczywiste. Czy lepiej, czy gorzej? Trudno póki co ocenić – niby mniej pytań to szansa na zrobienie mniejszej ilości błędów. Z drugiej jednak strony jak się jakoś krzywo cokolwiek wylosuje/trafi to będzie niefajnie. No cóż, korzystając z faktu, że delikatna niemoc gardła wykluczyła mnie z pracy zawodowej na parę dni douczam się cały czas i mam nadzieję, że niezależnie od ilości pytań wynik będzie satysfakcjonujący.

Pierwsze urodziny Stronnic Chlebika

Tadam! Właśnie tak – pierwsza rocznica powstania moje bloga programistycznego. Wierzyć się nie chce – wydaje się to nie tak wcale dawno – kupno Thinking in Java, instalacja NetBeans z nastawieniem na Javę. No i rzecz jasna – pierwszy wpis! Łezka się w oku kręci…

Przez ten rok Stronnice dorobiły się całkiem wiernego grona czytelników. Patrząc po statystykach odwiedzin widzę, że do “szefostwa” polskiej javosfery mi jeszcze sporo brakuje, ale daje to impuls do działania, aby ten stan rzeczy zmienić. Zwłaszcza, że sporo zapytań do Googla pokazuje link do moich wpisów, co jest wartością samą w sobie, a świadomość, iż ktoś oszczędził czas czy nauczył się czegoś nowego dzięki mej pisaninie jest bardzo miła.

Pomijając same zapisy na blogu – co się zmieniło w przypadku mojej osoby? Ano zdobyta wiedza gdzieś tam się kołacze po zakamarkach umysłu. Wiadomym jest, że na pewno nie napisałbym z palca szeregu rzeczy, ale po szybkim make-upie dałbym radę zawalczyć. Chyba trzeba się za jakąś robotą w Javowym świecie rozglądać – to chyba najlepsza metoda na ciągły rozwój jako programista. Czego zaś mogę sobie życzyć na następny rok? Pewnie jeszcze większej poczytności, ciekawych wpisów i z całą pewnością większej ilości wolnego czasu. Choć tego ostatniego to pewnie każdemu brakuje.

ProgramBash – Hibernate wkracza do gry

Jak pisałem w poprzednim wpisie na podpięcie bazy danych miał przyjść czas. No i ten czas właśnie nadszedł. W dzisiejszym wpisie zajmiemy się podpięciem do naszej aplikacji ORMa Hibernate i spróbujemy go zmusić do pracy z PostgreSQL. A kiedy już zmusimy to i może coś ładnego da się z tego wykrzesać. Zaczynamy.

Pierwszą rzecz, a mianowicie zaimportowane biblioteki do obsługi Hibernate mamy już za sobą. Podczas tworzenia projektu zaznaczyłem opcję mówiącą o imporcie tej jakże przydatnej biblioteki. Domyślnie ustawiłem dialekt na MySQL, jednakże po pobieżnym researchu okazało się, że u mnie na hostingu da się bez problemu zainstalować Postgresa w związku z tym zaczniemy od zmiany pliku konfiguracyjnego – wszak i lokalnie będę pracował z tym systemem bazodanowym.

Obslugiwany dialekt Hibernate znajdziemy spokojnie w źródłach tejże biblioteki, jednakże sterownik dla Postgresa już niekoniecznie. Zatem wypada ściągnąć najnowszą wersję sterownika i dodać do bibliotek w naszym projekcie (PPM na Libraries -> Add i wskazujemy plik ). Ja wrzuciłem swój do katalogu \WEB-INF\lib wraz z kilkoma innymi bibliotekami.
Edytujemy zatem plik hibernate.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.connection.url">jdbc:postgresql://localhost/bash:5432</property>
<property name="hibernate.connection.username">chlebik</property>
<property name="hibernate.connection.password">chlebik</property>

     <mapping resource="/hibernate/mapping/News.hbm.xml"/>

  </session-factory>
</hibernate-configuration>

Jak widać obok standardowych zapisów mówiących o dialekcie i takich tam dodałem już z góry oddzielny zapis o pliku odwzorowania. Pakiet, który będzie zawierał pliki odwzorowań dla Hibernate (jest to najzwyklejszy pakiet utworzony w katalogu ze wszystkimi innymi pakietami) będzie nazywał się com.wordpress.chlebik.mappings. Na pierwszy ogień zaimplementujmy coś prostego – choćby listę newsów pojawiających się zaraz po wejściu do serwisu. Plik News.hbm.cfg prezentuje się następująco:

<hibernate-mapping package="hibernate.mappings">
 <class name="com.wordpress.chlebik.News" table="news">
 <id name="id" type="long" column="id">
 <generator />
 </id>
<property name="adddate" column="adddate" type="integer" />
<property name="header" column="header" type="string" />
<property name="content" column="content" type="string" />
 <class>
</hibernate-mapping>

Jak widać nie jest on specjalnie skomplikowany. Relacji nie ma, raptem 4 pola, wszystko w miarę proste i oczywiste. Jest to odwzorowanie zwykłego POJO, którego zresztą trzeba stworzyć.

package com.wordpress.chlebik;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * Klasa, ktora ma za zadanie byc beanem wystepujacym jako news na portalu
 *
 * @author Michal Piotrowski
 */
@Entity
@Table(name="news")
public class News {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String header;
    private String content;
    private Integer adddate;

    public News() {
    }

    public News( String header, String content, Integer adddate ) {
        this.header = header;
        this.content = content;
        this.adddate = adddate;
    }

    // Gettery
    public String getHeader()
    {
        return header;
    }

    public String getContent()
    {
        return content;
    }

    //  To jest konieczne by moc formatowac date za pomoca znacznikow JSF
    public Date getAdddate()
    {
        Date dateDateObject = new Date();
        long dateInMilis = ((long)adddate)*1000;
        dateDateObject.setTime(dateInMilis);
        return dateDateObject;
    }

    protected Long getId()
    {
        return id;
    }

     // Settery - bardziej dla poprawnosci niz potrzeby
    public void setHeader( String header )
    {
        this.header = header;
    }

    public void setContent( String content )
    {
        this.content = content;
    }

    public void setAdddate( Integer adddate )
    {
        this.adddate = adddate;
    }

    protected void setId( Long id )
    {
        this.id = id;
    }
}

Mamy odwzorowanie, mamy POJO, co teraz? Normalnie wypadałoby zrobić dwie rzeczy – zapewnić sobie jeszcze jedną klasę, która zajęła by się tylko dostępem do danych. Czyli np. wyciąganiem obiektów, ich zapisywaniem i takimi tam. W przypadku zwykłych newsów, które na razie będą dodawane bezpośrednio przez bazę (tworzenie panelu administracyjnego dla mojej skromnej edukacyjnej aplikacji uważam za pozbawione sensu), nie ma absolutnie potrzeby rozgraniczanie logiki biznesowej na kolejne warstwy. Przykład jest póki co banalny, myślę że nie popełnię większego naduzycia jeśli po prostu wrzucę metodę wyciągającą ostatnie newsy w komponencie zarządzanym i na tym poprzestaniemy.

Teraz sprawa druga – dostęp do bazy danych. Jak piszą autorzy mojej książki o Hibernate obiekt, który zawiaduje połączeniami do bazy danych i całym tym jarmarkiem to SessionFactory. Jest to jednakże obiekt “ciężki” (heavyweight object), dlatego najlepiej mieć go raptem jeden na całą aplikację. Co zatem trzeba zrobić? Ano jak piszą mądrzy ludzie najlepiej zaimplementować klasę, która będzie trzymała takowy “ciężki” obiekt w formie zmiennej statycznej i w ten sposób po uruchomieniu aplikacji będziemy mogli wyciągać tylko obiekty sesji z istniejącej już fabryki.

Robimy to następująco. Wybieramy sobie pakiet, w którym chcemy takowy obiekt umieścić i prawy przycisk myszy -> New -> Other -> Hibernate -> Hibernate Util. Dzięki temu mamy od razu stworzoną klasę, która wszystko pięknie nam obsłuży. U mnie wygenerowany plik wygląda tak:


package com.wordpress.chlebik;


import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;

/**
 * Hibernate Utility class with a convenient method to get Session Factory object.
 *
 * @author chlebik
 */
public class ProgramBashUtil {
    private static final SessionFactory sessionFactory;

    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml) 
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Log the exception. 
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

Uff. Mamy chyba wszystko. Pozostaje nam podpiąć pod główną stronę pięknego managed-beana i jesteśmy prawie w domu. Wpierw XML (plik faces-config.xml), potem kod Javy:

<managed-bean>
  <managed-bean-name>NewsBean</managed-bean-name>
  <managed-bean-class>com.wordpress.chlebik.NewsBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
 </managed-bean>

No i teraz kod Javy. Nasze ziarenko będzie posiadało tylko jedną metodę – getNews, co pozwoli wylistować wszystkie newsy z bazy. Listing zatem przedstawia się dość prosto:

package com.wordpress.chlebik;

import java.io.Serializable;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;


public class NewsBean implements Serializable {
       
    public NewsBean() {        
    }

   
    public List<News> getNews()
    {
        SessionFactory sessionFactory = com.wordpress.chlebik.ProgramBashUtil.getSessionFactory();
        Session session = sessionFactory.openSession();

        List<News> newsy = session.createQuery("from News order by adddate DESC").list();
        return newsy;
    }
}

Ano i tyle. Od tej pory wystarczy w plikach JSP odwołać się do zapisu #{newsBean.news} i mamy piękną listę newsów. Ja wrzuciłem listowanie newsów na stronę główną w taki oto sposób:

<rich:dataList var="news" value="#{newsBean.news}" rowClasses="newsElement">

  <div>
      <div class="newsHeader"><h:outputText value="#{news.header}"/></div>
      <div class="newsDate">
         <h:outputText value="#{news.adddate}">
             <f:convertDateTime type="date" dateStyle="full" />
        </h:outputText>
      </div>
      <div class="newsContent"><h:outputText value="#{news.content}" /></div>
      
  </div>

</rich:dataList>

Rzecz jasna klasy CSSa również ładnie podpiąłem i stąd ładny widok. Nieprawda?

glownaHibernateProgramBash