JAVA exPress > Archive > Issue 3 (2009-03-08) > Kubek Kawy - czyli alternatywny kurs Javy, cz. III

Kubek Kawy - czyli alternatywny kurs Javy, cz. III

Długo zastanawiałem się nad tym co powinniśmy zrobić na pierwszych prawdziwych zajęciach z Javy (czytaj będziemy w końcu programować). Weźmiemy się za programowanie, bo większą część teorii już przebrnęliśmy w dwóch poprzednich częściach, ale co będziemy programować.

Środowisko

Zanim napiszemy pierwszy program, należy włączyć sobie jakieś pisadło. Na rynku jest wiele środowisk przeznaczonych do programowania. Generalna nazwa to IDE od angielskiego Integrated Development Environment - zintegrowane środowisko programowania. Narzędzie takie zapewnia zazwyczaj kilka podstawowych opcji jak:

- podświetlanie składni,

- sprawdzanie poprawności składni,

- automatyczna konfiguracja kompilatora,

- debugger.

Pierwsze dwa punkty są minimalnym minimum. Bez tego nie można mówić o IDE nawet jak o edytorze kodu. Trzeci punkt nie jest obowiązkowy, ale zazwyczaj dostarczany nawet z najprostszymi edytorami. Ostatni punkt też nie jest obowiązkowy, ale IDE aspirujące do miana poważnego narzędzia powinno posiadać debugger.

Od tego punktu zaczynamy prawdziwą alternatywność tego kursu. Zazwyczaj tradycyjne kursy prowadzone na uczelniach czy też w ramach wydawnictw książkowych zawierają magiczne zdanie "otwórz ulubiony edytor tekstu". Co pewnego razu kolega podsumował "Można pisać w Excelu?". Oczywiście, że można, pytanie brzmi czy nie łatwiej użyć do tego zadania odpowiedniego narzędzia? Ja nie powiem wam o ulubionym edytorze. Od dziś przez pewien czas waszym ulubionym edytorem jest Eclipse 3.4.1 Classic. Pobieramy go w następujący sposób:

- Wchodzimy na www.eclipse.org.

- Naciskamy "Download".

- Z listy wybieramy "Eclipse 3.4.1 Classic".

- Obok napisu "Download from" będzie link do pliku.

- Zapisujemy plik na dysku.

- Rozpakowujemy zawartość.

- Uruchamiamy.

- Zostaniemy poproszeni o wskazanie "Workspace", jest to katalog roboczy, tu będą nasze projekty.

- Naciskamy ctrl+n i z listy wybieramy Java - Java Project. Można sobie pomóc wpisując na górze okna "java project"

- Nazywamy nasz projekt w jakiś rozsądny sposób, na przykład "Kubek Kawy fajny kurs java".

- Naciskamy "finish". Jak wyskoczą nam jakieś okienka to naciskamy "OK". Na tym etapie raczej nic jeszcze nie zepsujemy.

- Powinno ukazać się nam coś w stylu rysunku 1.

Rysunek 1. Coś co będzie wam się śniło po nocach

Teraz jeszcze kilka słów co my tu mamy i bierzemy się do pisania kodu.

1. Lista projektów, plików, bibliotek w projektach. W praktyce podgląd aktywnej zawartości przestrzeni roboczej.

2. Tu będą otwierać się pliki. Edytor.

3. Słówko "Problems" mówi samo za siebie. Tu też będzie podgląd konsoli.

4. Różne pomocne okna. Później sam odkryjesz co i jak.

5. Masa różnych przycisków. Pozwalają na tworzenie nowych plików, zapisywanie, drukowanie, ale też na uruchamianie kompilatorów czy debuggerów.

W miarę posuwania się naszych prac odkryjesz zapewne do czego służy jakieś 90% opcji i przycisków. Na razie nie zawracaj sobie tym głowy. Możesz poeksperymentować, ale zakładam, że nie bardzo znasz się na programowaniu więc i tak niczego nie wykorzystasz.

Pierwszy program

Czas na pierwszy program. Naciskamy ctrl+n wybieramy "Java-package" i jako nazwę podajemy nazwę pakietu. Pakiety służą przede wszystkim do logicznej organizacji kodu. W praktyce organizują go też fizycznie na dysku. Działają trochę jak adres internetowy, zapewniając nie tylko podział logiczny, ale też unikalność nazw. O tym wkrótce. Na razie piszemy pierwszy program. Ja mój pakiet nazwałem pl.koziolekweb.javaexpress.kubekkawy.cz3. Znowu naciskamy ctrl+n i wybieramy "java-class". Nazywamy naszą nową klasę "PierwszyProgram" i zaznaczamy opcję "public static void main(String[] args)". Otrzymamy coś takiego jak poniżej:

 
            package pl.koziolekweb.javaexpress.kubekkawy.cz3;
 
            public class PierwszyProgram {
 
                /**
* @param args
*/
public static void main(String[] args) { // TODO Auto-generated method stub   } }  

Metoda main(String[] args) jest punktem, od którego startuje każdy program w języku Java. Tyle trzeba obecnie o niej wiedzieć. Zamiast standardowego "Hello world!" sprawdźmy, który dzień tygodnia dziś mamy. Program realizujący to zadanie wygląda tak:

 
        package pl.koziolekweb.javaexpress.kubekkawy.cz3;
 
        import java.util.Calendar;
        import java.util.GregorianCalendar;
 
        public class PierwszyProgram {
 
            /**
* @param args
*/
public static void main(String[] args) { Calendar calendar = GregorianCalendar.getInstance(); int dzień = calendar.get(Calendar.DAY_OF_WEEK); System.out.println("dziś mamy " + dzień + " dzień tygodnia"); } }  

Niedziela jest pierwszym dniem tygodnia, poniedziałek drugim itd. W liniach 3 i 4 znajdują się polecenia importu odpowiednich klas. Jeżeli chcemy użyć jakiejś klasy w programie, musimy powiedzieć kompilatorowi czego chcemy używać. Java ma ścisłą kontrolę typów, ale też przymusowe dostarczanie implementacji klas i interfejsów w procesie kompilacji. Jeżeli spotkałeś się z językiem C/C++, to pamiętasz pewno, że dało się tam wymusić kompilację kodu bez sprawdzania czy istnieją odpowiednie zależności z poleceń include. W javie takiego przekrętu nie da się zrobić. Szkoda, ale z drugiej strony ma to zalety. Oczywiście nie wszystko trzeba importować. W 14 linii jest używana klasa System, ale nie ma importu. Kompilator automatycznie importuje wszystkie klasy z pakietu java.lang. Jeżeli mamy do zaimportowania kilka klas z jakiegoś pakietu, to można zastąpić je zapisem "z gwiazdką", czyli zamiast nazwy klasy wrzucamy '*' i tyle. Oczywiście IDE po formatowaniu kodu ograniczy to do wymaganych klas. Zresztą, czy to jest ważne na tym etapie? Moim zdaniem nie.

Naciskamy mały zielony przycisk na górze. W ten sposób zostanie uruchomiony nasz program. Na dole otworzy się podgląd konsoli, w którym powinniśmy zobaczyć:

        dziś mamy 7 dzień tygodnia
        

No to na tyle jeśli chodzi o pierwszy program. Czas zająć się czymś zabawniejszym niż wypisywanie głupot w konsoli.

Interakcja z użytkownikiem

No nie do końca porzucimy konsolę. Na chwilę obecną bez sensu jest pchanie się w fajerwerki graficzne, jak nie do końca potrafimy programować proste rzeczy. Co za dużo to niezdrowo. Metoda main(), jako parametr przyjmuje tablicę obiektów String. Tablica ta reprezentuje argumenty przekazane do programu za pomocą linii poleceń. Czas zatem trochę skomplikować zadanie i sprawdzać czy dziś mamy dzień podany przez użytkownika. W tym celu musimy zrobić dwie rzeczy. Po pierwsze dopisać odpowiedni kod do naszego programu, ale to za chwilę. Po drugie umieć uruchomić go z parametrami. W tym celu wybieramy z górnego menu Run>Run Configuration> zakładka Arguments i w polu "Program arguments" wpisujemy interesujący nas numer dnia tygodnia. Pamiętamy, że tydzień ma siedem dni, numerowanych od 1, a pierwszym dniem jest niedziela. Klikamy "Run", zaskoczyło to ok. Czas na programowanie. Ostrzegam, kod będzie niebanalny.

 
        package pl.koziolekweb.javaexpress.kubekkawy.cz3;
 
        import java.util.Calendar;
        import java.util.GregorianCalendar;
        import java.util.regex.Matcher;
        import java.util.regex.Pattern;
 
        public class PierwszyProgram {
 
            /**
* @param args
*/
public static void main(String[] args) { if (args.length == 0) { System.out.println("Nie podano argumentów!"); System.exit(0); } String dzieńPodanyPrzezUżytkownika = args[0];   Pattern pattern = Pattern.compile("^[0-9]+$"); Matcher matcher = pattern.matcher(dzieńPodanyPrzezUżytkownika.trim());   if (!matcher.matches()) { System.out.println("Proszę podać liczbę jako parametr"); System.exit(0); }   Calendar calendar = GregorianCalendar.getInstance(); Integer dzień = calendar.get(Calendar.DAY_OF_WEEK); Integer dzieńPPUInteger = Integer.parseInt(dzieńPodanyPrzezUżytkownika);   System.out.println("Czy dziś jest " + dzieńPodanyPrzezUżytkownika + " dzień tygodnia? " + (dzień.equals(dzieńPPUInteger) ? "tak" : "nie")); } }  

Fajne? Nie jakieś tam prościutkie wypisywanie parametrów jak w kursach bywa. Linie 14 do 17 zawierają proste sprawdzenie, czy przekazano parametry. Jeżeli użytkownik nie przekazał parametrów, długość tablicy jest równa 0, to wyświetlany jest komunikat i program kończy działanie. W linii 18 tworzymy sobie zmienną, której jedynym zadaniem jest sprawienie, że kod będzie czytelniejszy. Można oczywiście pracować, ze zmienną args, ale może to spowodować zaciemnienie kodu. Pamiętajmy, że nazwy zmiennych powinny mieć nazwy znaczące. Patrząc na zmienną powinniśmy wiedzieć co reprezentuje.

Linie od 20 do 26 służą do sprawdzenia, czy podany parametr jest liczbą całkowitą większą od 0. Do przeprowadzenia tej operacji użyłem wyrażeń regularnych. Jest to narzędzie, które pozwala analizować tekst przy pomocy pewnych wzorców. Na razie nie trzeba o tym więcej wiedzieć, ale jak jesteś zainteresowany to odsyłam do Wikipedii. Podstawowe informacje zamieszczam w ramce.

Wyrażenia regularne – regexp

Wyrażenia regularne służą do analizowania tekstu za pomocą wzorców. Tekst jest "przykładany" do wzorca i sprawdzany czy spełnia warunki. Tworzenie wzorców to skomplikowane zagadnienie, ale podstawowe wzorce można opanować w kilka minut. W Javie wzorzec jest podawany jako ciąg znaków. Istnieją też inne sposoby podawania wzorców w innych językach. Podstawowe wzorce:

Cyfry:

[0-9] lub \d – dowolna cyfra

\D lub [^0-9] – dowolny znak nie będący cyfrą

Białe znaki:

\s – dowolny znak biały

\S – dowolny znak nie będący znakiem białym

\t – znak tabulacji [Tab]

\n – znak nowej linii

\r – znak powrotu karetki

Litery:

[a-zA-Z] lub \w – dowolna litera

[^a-zA-Z] lub \W – dowolny znak nie będący literą

Znaki:

. – dowolny znak

Krotności:

Krotność określa ile razy znak może się powtórzyć.

x{n} – n-krotne wystąpienie znaku x

x{n,} – co najmniej n-krotne wystąpienie znaku x

x{0,n} – co najwyżej n-krotne wystąpienie znaku x

x{n,m} – co najmniej n-krotne i maksymalnie m-krotne wystąpienie znaku x

x+ – co najmniej jednokrotne wystąpienie x

x? – nie więcej niż jednokrotne wystąpienie x odpowiednik x{0,1}

x* – możliwość wystąpienia x odpowiednik x{0,}

Znaki specjalne:

^ – jeżeli jest umieszczony na samym początku wzorca oznacza początek wzorca. W przeciwnym wypadku oznacza zaprzeczenie.

$ – umieszczony na końcu wzorca oznacza koniec wzorca. Nie należy mylić ze znakiem końca linii.

\ – znak "ucieczki" jeżeli znak za tym znakiem jest znaczący lub specjalny to jego cechy zostaną zignorowane i będzie traktowany jak zwykły tekst.

Należy pamiętać, że w Javie obiekt String ma dodatkowe właściwości dotyczące znaków specjalnych. Szczególnie należy uważać na ilości znaku backslash '\'. Jeżeli będzie go za mało lub za dużo to może okazać się, że wzorzec jest nieprawidłowy lub oznacza coś innego. Poniżej przykładowe wzorce, które różniąc się ilością znaków backslash oznaczają zupełnie różne rzeczy:

1. "^\d$" – nieprawidłowa sekwencja znaków. Program się nie skompiluje.

2. "^\\d$" – jedna cyfra. Znak ucieczki zastosowany tylko do znaku '\', działa w ramach obiektu String. Wyrażenie regularne "widzi" tylko jeden znak '\'.

3. "^\\\d$" – nieprawidłowa sekwencja. Program się nie skompiluje.

4. "^\\\\d$" – ciąg znaków "\d", a nie cyfra. Znak ucieczkowy zastosowany najpierw jak w przykładzie 2, a następnie dodatkowo w ramach wzorca. Przy czym należy pamiętać, że uciekamy też od znaku '\' we wzorcu. Swoista ucieczka do znaku ucieczki.

Na zakończenie do analizy pozostawiam prosty wzorzec. Zgadnij co opisuje:

"^[-]?[0-9]*\\.?[0-9]*$"

Oczywiście pada pytanie, dlaczego analizę robimy za pomocą tak trudnego zagadnienia jakim są wyrażenia regularne. Odpowiedź brzmi, ponieważ jest to prawidłowe podejście. Bardzo często jako przykład takiego sprawdzania jest podawany kod podobny do poniższego:

 
        String liczbaString = "000";
        try {
            Integer liczbaInteger = Integer.parseInt(liczbaString);
        } catch (NumberFormatException e) {
            System.out.println("podana liczba jest nieprawidłowa!");
        }
 

Ten kod to "tru zuo" w najczystszej postaci. Wywodzi się z czasów, gdy wiele rzeczy można było zaprogramować za pomocą obsługi przerwań systemowych. Mówi się też czasami o programowaniu sterowanym wyjątkami. My mamy Javę, która posiada odpowiednie mechanizmy i narzędzia wydajnie zastępujące pewne pomysły.

W linii 30 następuje zamiana napisu na liczbę. Wszystkie klasy reprezentujące liczby mają metody parse(), które pozwalają zamienić ciąg znaków na liczbę. Ostatnie linijki programu są dość skomplikowane, ale nikt nie powiedział, że będzie łatwo. Generalnie jeżeli wykonujemy dodawanie obiektów String i innych obiektów to domyślnie wywoływane są metody toString() lub przeprowadzana konwersja z typów prostych. W linii 34 wykorzystany jest dodatkowo operator trójargumentowy w celu uniknięcia dodatkowej instrukcji if.

Pełna interakcja

Na zakończenie tej części mam dla ciebie zadanie domowe. Poniżej przedstawiam program, który zamiast argumentów będzie pytał użytkownika o liczbę i mówił czy odpowiada ona aktualnemu dniu tygodnia. Na jego podstawie napisz program, który będzie odpowiadał na pytanie o datę urodzin. Czyli użytkownik będzie podawał datę, a program zdecyduje czy użytkownik ma dziś urodziny czy też nie.

 
        package pl.koziolekweb.javaexpress.kubekkawy.cz3;
 
        import java.util.Calendar;
        import java.util.GregorianCalendar;
        import java.util.Scanner;
        import java.util.regex.Matcher;
        import java.util.regex.Pattern;
 
        public class PierwszyProgram {
 
            /**
* @param args
*/
public static void main(String[] args) { Scanner scanner = new Scanner(System.in);   System.out.println("Podaj liczbę do sprawdzenia"); String dzieńPodanyPrzezUżytkownika = scanner.nextLine();   Pattern pattern = Pattern.compile("^[0-9]+$"); Matcher matcher = pattern.matcher(dzieńPodanyPrzezUżytkownika.trim());   if (!matcher.matches()) { System.out.println("Prosze podać liczbę"); System.exit(0); }   Calendar calendar = GregorianCalendar.getInstance(); Integer dzień = calendar.get(Calendar.DAY_OF_WEEK); Integer dzieńPPUInteger = Integer.parseInt(dzieńPodanyPrzezUżytkownika);   System.out.println("Czy dziś jest " + dzieńPodanyPrzezUżytkownika + " dzień tygodnia? " + (dzień.equals(dzieńPPUInteger) ? "tak" : "nie")); } }  

W kolejnym odcinku

Przechowywanie danych. Interakcja z użytkownikiem ciąg dalszy. Dwie rzeczy na raz – bardzo podstawy wątków.

Nobody has commented it yet.

Only logged in users can write comments

Developers World