Etap 1: Hello World!
Cześć! Bardzo nam miło powitać Cię w pierwszym etapie Wyzwania Java z Kodillą. Przekonasz się, że choć język Java słusznie ma opinię złożonego, to jednak opanowanie go jest możliwe. Wszystko, czego potrzebujesz, by zacząć, to trochę wolnego czasu, motywacji i samozaparcia. Prawdziwa programistyczna przygoda jest tuż na wyciągnięcie ręki. Powodzenia!
Plan pracy
Ponieważ język Java jest nieco bardziej skomplikowany niż HTML i CSS, to zanim przejdziemy do pisania naszej wyszukiwarki lotów, będziemy musieli poświęcić nieco czasu na opanowanie najważniejszych pojęć i wykonanie kilku ćwiczeń “na sucho”. Dzięki nim szybko złapiesz podstawy języka Java i będziesz w stanie stopniowo przejść do bardziej złożonych zagadnień.
Narzędzia
Pisanie w języku Java wymaga skonfigurowanego środowiska developerskiego, ale nie przejmuj się – na potrzeby tego Wyzwania uprościmy sobie sprawę i zamiast instalować Javę wraz z przyległościami na komputerze, skorzystamy z gotowego edytora online.
Kliknij ten link, aby przejść do edytora: https://repl.it/languages/java
Co tam widzimy? Sam edytor jest podzielony na dwie kolumny: w lewej będziemy pisać kod, a w prawej (w tak zwanej konsoli) zobaczymy rezultaty naszych wysiłków. Cała nasza aplikacja będzie wyświetlona w formie tekstowej w prawej kolumnie (po zalogowaniu do Repl.it widok edytora będzie zawierał 3 kolumny, z lewej strony pojawi się dodatkowa kolumna z listą plików w naszym projekcie - na początku jest jeden: Main.java).
Istnieją narzędzia umożliwiające dodanie interfejsu graficznego do programów Javy, ale jest to bardziej zaawansowana opcja, którą poznasz na naszym bootcampie, gdy już dość dobrze opanujesz sam język. Zawsze na początku przygody z Javą developer widzi tylko tekstowy wynik swojego kodu :)
Hello World!
Jak widzisz, już przy pierwszym otwarciu edytora znajduje się w nim kilka linijek kodu Javy (w środkowej kolumnie). Jest to działający, prosty program! Kliknij zielony przycisk "Run" na górze edytora:

Po chwili, po prawej, wyświetli się napis "Hello world!":

Przywitanie się ze światem (czyli właśnie nasze "Hello World!") to zwykle pierwsze ćwiczenie przy opanowywaniu jakiegokolwiek języka programowania :)
No dobrze, wiemy już, że nasz pierwszy "program" działa. Przyjrzyjmy się teraz samej budowie języka Java! Zerknij na środkową kolumnę edytora:

Na razie jej zawartość może wydawać się czarną magią, ale spokojnie – już sobie wszystko wyjaśniamy.
Zacznijmy od pierwszej linijki:

Definiujemy w niej klasę o nazwie Main
. Czym jest klasa? Mówiąc najprościej, klasa to szablon, na podstawie którego będą tworzone obiekty. Kolejne nowe pojęcie! Posłużmy się więc metaforą. Posiadasz zapewne telefon komórkowy – jest to konkretny obiekt, wyprodukowany na podstawie jakiegoś wzorca (szablonu). Identycznych telefonów są tysiące, jeśli nie miliony, szablon natomiast jest jeden.
Podobnie jest w Javie (która jest językiem obiektowym, czyli operującym właśnie na obiektach): mamy pewien szablon (klasę), na podstawie którego tworzymy konkretne obiekty. Pamiętaj, że cała zawartość klasy musi znajdować się w nawiasach klamrowych:

Zauważ przy okazji tekst zaczynający się od dwóch znaków slash (//
) w powyższym fragmencie kodu. Jest to komentarz, który nie będzie wyświetlany w naszej aplikacji – komentarze służą developerom np. do robienia notatek w kodzie bądź też czasowego wyłączania niektórych fragmentów kodu.
No dobrze, wiemy już czym są klasy i obiekty. Zidentyfikowaliśmy też klasę w naszym kodzie. Do obiektów jeszcze wrócimy, na razie badajmy dalej klasę Main
. W kolejnej linijce widzimy następujący zapis:

Jest to metoda, zwana też funkcją. Wracając do naszej metafory o telefonie komórkowym: każdy telefon ma jakieś funkcje, np. dzwonienie, wysyłanie wiadomości czy robienie zdjęć. Powyższa metoda jest specjalnym typem metody – od niej zaczyna się każdy program w Javie. Można to porównać z uruchomieniem telefonu – jest on bezużyteczny, jeśli go nie włączymy.
Podobnie jak w przypadku klasy, zawartość metody musi być umieszczona w klamrach:

Trzecia linijka – System.out.println("Hello world!");
– odpowiada za wyświetlenie tekstu w konsoli po prawej stronie. Czemu "Hello world!" zostało umieszczone w cudzysłowie? To jeden z typów danych – String. Cokolwiek umieszczone w cudzysłowie staje się Stringiem, czyli ciągiem znaków – inaczej mówiąc jest to tekst. Konstrukcja SSystem.out.println("Hello world!");
to wywołanie metod println
z klasy out
– metodę wywołujemy po kropce, ale jeszcze będziemy to omawiać.
Pierwszy program działa, ale nie napisaliśmy samodzielnie ani jednej linijki kodu. Czas to zmienić!
Zaczynamy kodowanie
Zacznijmy od skasowania System.out.println("Hello world!");
. Wprowadzimy sobie teraz nowe pojęcie: zmienna. W uproszczeniu, zmienna to "pudełko", w którym możemy przechowywać jakąś wartość, a następnie odwoływać się do niej w naszym kodzie. Spójrz na przykład:

Co to oznacza? Do zmiennej typu String o nazwie example przypisujemy obiekt String z wartością Hello World. Nazwa zmiennej potrzebna jest nam, ponieważ sam obiekt nie ma nazwy, tworzony jest gdzieś w pamięci. Jedynym uchwytem (wskaźnikiem), za pomocą którego możemy odnieść się do obiektu jest właśnie zmienna.
Przejdźmy do edytora kodu. Wspomnianą zmienną możemy utworzyć w dwóch miejscach – w klasie oraz w metodzie. Wybieramy drugą opcję, do pierwszej jeszcze wrócimy.

Zapisz projekt klikając “Save” na górze edytora, a potem kliknij “Run”. Nic się nie wyświetliło! Dlaczego? Przyczyna jest prosta: utworzyliśmy zmienną, przypisaliśmy do niej obiekt, ale nigdzie jej nie wyświetlamy. Masz pomysł, jak to zmienić? Spróbuj wyświetlić naszą nową zmienną, używając znanej Ci już konstrukcji System.out.println()
. Wstaw ją po prostu w tym miejscu, gdzie w początkowym kodzie było wpisane "Hello World!".
Udało się? Rozwiązanie powinno wyglądać tak, jak poniżej, a nasz projekt po kliknięciu "Run" powinien witać się ze światem:

Znakomicie! Wiemy, jak utworzyć zmienną typu String i jak ją wyświetlić. Ciągle to jednak dość mało, więc płynnie przechodzimy do definiowania klas i tworzenia obiektów.
Ćwiczenie 1: klasy, obiekty, metody
Czy pamiętasz metaforę z telefonem komórkowym, na której tłumaczyliśmy pojęcia klasy i obiektu? Wykorzystamy teraz ten przykład do napisania naszej pierwszej aplikacji treningowej.
1. Na samym początku stwórz w kodzie nową klasę: MobilePhone
. Powinna ona znajdować się po zamknięciu ostatniej klamry klasy Main
.
Efekt powinien wyglądać następująco:

2. Nasza klasa na razie jest pusta – czym możemy ją wypełnić? Jak wiemy, każdy telefon ma specyficzne cechy – w świecie obiektowym mówimy na nie właściwości. Są to po prostu zmienne, które istnieją w danej klasie. Utwórz wewnątrz klasy MobilePhone
zmienną o nazwie weight
i typie String z wartością 200g
.

3. Mamy gotowy szablon, czas na utworzenie obiektu na jego podstawie. Obiekty tworzymy w następujący sposób:
TypZmiennej nazwaZmiennej = new NazwaKlasy();
TypZmiennej
to zazwyczaj to samo, co NazwaKlasy
, jednak nie zawsze musi tak być (szczegółowo mówimy o tym na Bootcampie Javy). Stwórzmy obiekt typu MobilePhone
w metodzie Main
.

Mamy już nieco więcej kodu w naszej aplikacji, ale gdy klikniesz “Run”, nic się nie wyświetli. Z doświadczenia już wiemy, że brakuje wywołania metody wypisującej tekst. Spróbuj więc dodać taką linijkę:

W efekcie zobaczysz w konsoli tekst MobilePhone@2a139a55
lub podobny ciąg znaków. Nic nam to nie mówi. Warto się na chwilę zatrzymać i zastanowić, co chcemy wyświetlić. Przekazując zmienną o nazwie phone
do System.out.println()
mówimy kompilatorowi, że chcemy wyświetlić cały obiekt. My jednak chcemy na razie pokazać samą wagę telefonu, czyli interesuje nasz pokazanie właściwości weight
z obiektu phone
. Czy pamiętasz, jak mówiliśmy, że metodę z klasy wywołujemy po kropce? Tutaj sytuacja będzie bardzo podobna:

Użycie phone.weight
rozwiązało nasz problem. Odwołaliśmy się do zmiennej weight
z obiektu o nazwie phone
. Zapamiętaj, że możemy dostać się do zmiennych w klasie, stosując zapis nazwaObiektu.nazwaZmiennej
.
4. Do tej pory utworzyliśmy klasę MobilePhone
ze zdefiniowaną “na sztywno” właściwością weight
. W konsekwencji, każdy utworzony na podstawie tej klasy obiekt będzie miał taką samą wagę. Tak nie powinno być! W końcu telefony-cegły sprzed kilku dekad i współczesne filigranowe smartfon to bardzo różne przypadki :) Każdy szablon jest tylko wzorcem, więc chcielibyśmy mieć możliwość ustawienia wagi w trakcie tworzenia obiektu. Jest na to sposób – konstruktor. Jego składnia wygląda następująco:

W kodzie będzie to wyglądało tak:

Zmian jest sporo; zacznijmy od linijki 11. Tworzymy w niej konstruktor klasy MobilePhone
, który przyjmuje argument typu String. Wewnątrz konstruktora (lub, mówiąc profesjonalnie, w jego ciele), otrzymaną wartość przypisujemy do zmiennej w klasie (przypisywanie zawsze odbywa się z prawej do lewej). W linii nr 3, tworząc obiekt typu MobilePhone
, wywołujemy konstruktor oraz przekazujemy wartość, jaka ma być przypisana do zmiennej weight
.
Podsumowanie: po co nam konstruktor?
Zaletą użycia konstruktora jest to, że możemy utworzyć wiele różnych obiektów na podstawie jednego szablonu. Każdy z obiektów może się różnić przekazanymi wartościami. Co ważne, każdy obiekt tworzony jest od zera i nic nie wie o poprzednim obiekcie tego samego typu.
Utwórzmy zatem kilka nowych obiektów na podstawie naszego konstuktora. Przyjrzyj się, w jaki sposób przypisujemy każdemu obiektowi z osobna jego wagę (czyli wartość zmiennej weight
) i jak wyświetlamy tę wartość w konsoli:

5. Jedna zmienna w klasie to za mało. Dodajmy cenę do naszych telefonów! Masz pomysł, jak to zrobić? Cena będzie liczbą, więc zamiast ciągu znaków (String) użyjemy zmiennej typu int (integer – liczba całkowita).
- Pod zmienną
weight
w klasieMobilePhone
dodaj zatem zmienną typu int o nazwieprice
:int price;
- Następnie przekaż ją do konstruktora, zmieniając fragment
public MobilePhone(String weight)
napublic MobilePhone(String weight, int price)
. - Na końcu dodaj odwołanie do tej zmiennej w konstruktorze, tuż pod odwołaniem do zmiennej
weight
:this.price = price;
Cały kod powinien wyglądać tak, jak poniżej:

6. Czy domyślasz się, czego brakuje w naszym kodzie? Oczywiście: nigdzie nie wyświetlamy naszej nowej zmiennej. Moglibyśmy to zrobić w ten sposób:

Nie wydaje się on jednak zbyt elegancki. Na pewno przy większej liczbie obiektów będzie tworzyć bałagan w kodzie. Możemy połączyć zmienne w trakcie wyświetlania:

Operator +
łączy Stringi (ta operacja fachowo nazywa się konkatenacją). Zapis jest lepszy, ale można wyobrazić sobie sytuację, gdy będziemy mieć 10 zmiennych w klasie MobilePhone
. Rozwiązaniem problemu jest metoda. Samo pojęcie w kontekście metody public static void Main
już wyjaśniliśmy. Teraz zgłębimy temat, zaczynając od wzorca metody:

public
to modyfikator dostępu, który definiuje,gdzie metoda może być widoczna. Na początku stosujmy zawsze public
(widoczna wszędzie).
String
to typ zwracany – metoda wykonuje jakieś działanie, którego wynikiem będzie obiekt typu String
. Specjalnym typem zwracanym jest void
– określa, że metoda nie będzie nic zwracać (przydatne, gdy np. chcemy wyświetlić tekst wewnątrz metody).
Metoda może, ale nie musi przyjmować argumenty, podobnie jak konstruktor. Jeśli chcemy przekazać jakiś argument, najpierw musimy określić jego typ, następnie nazwę, która będzie używana wyłącznie wewnątrz tej metody.
Wróćmy do naszego kodu. Spróbuj utworzyć metodę, która nic nie zwraca, jednak wyświetla wagę i cenę w ciele metody. Następnie dodaj metodę, która zwraca Stringa składającego się z wagi i ceny telefonu. Nie zapomnij o wywołaniu obu metod!
Rozwiązanie powinno być podobne do zaprezentowanego:

Omawianie zacznijmy od metody, która w ciele wyświetla wartości obiektu, z którego została wywołana:

Metoda wyświetla coś w ciele, więc nic nie zwraca – typ void
. Nie przyjmuje również argumentów. this.weight
oraz this.price
odnoszą się do wartości w danym obiekcie – słowami moglibyśmy powiedzieć do obiektu: "Podaj wartość wagi oraz podaj wartość ceny". this
zawsze odnosi się do obiektu, na którym dana metoda została wywołana.
Druga metoda działa inaczej. Nic nie wyświetla, ale zwraca wartość – wykonuje operacje, których wynik jest zwracany na zewnątrz:

Ćwiczenie 2: zaczynamy wyszukiwarkę lotów!
Omówiśmy podstawowe zagadanienia przewidziane na pierwszy dzień. Mamy jednak z tyłu głowy cel, jaki został postawiony: napisać aplikację do wyszukiwania lotów. Co możemy zrobić po pierwszym dniu? Jesteśmy w stanie zdefiniować klasę opisującą lot, która będzie zawierać lotnisko startowe i końcowe.
- Utwórz nowy projekt w edytorze. Nie usuwaj projektu z telefonami: będzie on nam jeszcze potrzebny.
- W nowym projekcie usuń wyświetlanie "Hello World". Pod klasą
Main
stwórz klasęFlight
, a wewnątrz niej umieść dwie zmienne typu String:departure
orazarrival
. - Dalej, wewnątrz tej samej klasy, dodaj konstruktor typu
public
o nazwieFlight
. Powinien on przyjmować dwa argumenty typu String, które utworzyliśmy przed chwilą. - W ciele konstruktora przypisz argumenty do zmiennych o tych samych nazwach (np.
this.departure = departure;
).
Jeżeli nie pamiętasz, jak wykonać którąś z tych operacji, cofnij się do punktu 5. w ćwiczeniu z telefonami.
Cały kod powinien wyglądać tak:

Przeazalizuj go dokładnie i postaraj się zapamiętać, w jaki sposób zapisujemy w Javie poszczególne komendy.
Zadanie domowe
W ramach utrwalenia wiedzy, utwórz metodę w klasie Flight
, która zwróci informację o locie (Np.: "Flight from … to …").
Dodatkowo, poćwicz z klasą MobilePhone. Utwórz metody:
- wyświetlającą cenę,
- obniżającą cenę o 10%,
- zwiększającą cenę o wartość przekazaną w argumencie.
Uff! To tyle na dzisiaj. Do zobaczenia!