Cechy Javy przemawiające za jej wyborem
Przenośność - możesz uruchomić program na każdym systemie i sprzęcie, na którym istnieje implementacja wirtualnej maszyny Java.
Wygoda - podstawowe klasy i mechanizmy Java są zaimplementowane tak, że dostarczają programiście wygodnych w użyciu bibliotek, która w wielu przypadkach znacznie przyśpieszają tworzenie aplikacji.
Szybkość tworzenia aplikacji - w Java aplikacje pisze się szybciej niż w niektórych innych językach programowania. Wszystko dzięki użytecznym klasom i mądrze zaplanowanym bibliotekom, narzędziom oraz IDE.
Duże wsparcie ze strony twórców środowisk programowania - dzięki środowiskom IDE, takim jak NetBeans czy Eclipse, programy możesz tworzyć jeszcze szybciej i jeszcze wydajniej używając profesjonalnych narzędzi, które ułatwią tworzenie dużych aplikacji i panowanie nad tworzeniem oraz utrzymywaniem kodu.
Ciekawe możliwości tworzenia interfejsu użytkownika - możliwość dostępu do wygodnych w użyciu bibliotek i narzędzi pozwalających szybko i bezboleśnie stworzyć niezależny od systemu i przenośny interfejs graficzny dla aplikacji. Biblioteki graficzne udostępniają metody, które są dokładnie tym, czego potrzebujesz.
Duża ilość publikacji - w sieci jest sporo informacji na temat języka Java. Jest to ogromna zaleta szczególnie dla osób uczących się tego języka. W Internecie znaleźć można sporo przykładowego kodu, artykułów czy tutoriali.
Garbage collection, czyli automatyczne zwalnianie nieużywanych już obszarów pamięci
Wady, o których warto pamiętać Przeważnie programy uruchamiane pod maszyną wirtualną działają wolniej niż programy napisane w C++ (szczególnie czasochłonne jest uruchamianie aplikacji).
Użytkownik potrzebuje zainstalowanej maszyny wirtualnej javy (JVM), aby móc uruchomić nasz program.
Java ustępuje innym językom programowania (np. C++ lub Ada) w tworzeniu aplikacji czasu rzeczywistego.
Czego potrzebujesz, żeby zacząć
Java to nie tylko język programowania - to również środowisko uruchomieniowe, w którym działają programy, tak zwana Wirtualna Maszyna Java (Java Virtual Machine - JVM). Java jest zaliczana do języków kompilowano-interpretowanych - aby napisane przez nas programy zadziałały, wymagany jest kompilator, który przekształci kod źródłowy do tzw. byte code, czyli odpowiednika kodu maszynowego rozumianego przez JVM (w tej książce funkcjonuje również termin kod bajtowy). Zarówno JVM jak i kompilator są dostarczane za darmo przez twórców Javy - firmę Oracle. Najlepiej ściągnąć wszystko w jednym pakiecie, który obecnie nosi nazwę Java SE (Java Platform, Standard Edition). Java SE jest dostępna na wiele platform, w tym dla systemów 32- i 64-bitowych Windows i GNU/Linux. Jest to wszystko, czego potrzebujemy do rozpoczęcia pracy.
Windows W przypadku Windowsa można użyć implementację stworzoną przez Oracle. Można ją pobrać z ich oficjalnej strony internetowej. Wybieramy odpowiedni pakiet i wybieramy akceptujemy licencję Oracle. Następnie szukamy linków dla Windowsa 32 i 64 bitowego. Po pobraniu uruchamiamy instalator.
Kontynuując wybieramy, czy chcemy zainstalować dodatkowo kod źródłowy podstawowych bibliotek i COŚ TAM. Linux
Istnieje kilka implementacji Javy.Ubuntu Documentation > Community Documentation > Java My wybierzemy otwartą implementację OpenJDKStrona główna Openjdk, otwartej implementacji Javy.
Debian/Ubuntu W konsoli wpisujemy: $ sudo apt-get install openjdk-6-jdk openjdk-6-jre openjdk-6-doc
potem sprawdzamy:
java -version
Przykładowy wynik:
openjdk version "1.8.0_131" OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2ubuntu1.16.04.3-b11) OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
Arch Linux W konsoli wpisujemy (jako root): # pacman -S jdk7-openjdk jre7-openjdk lub jeśli potrzebujemy wersji 6: # pacman -S openjdk6
Następnie możemy sprawdzić działanie wpisując: $ javac -version
Java z punktu widzenia programisty
Środowisko uruchomieniowe i developerskie
Aby dobrze programować, warto zrozumieć, jak wygląda całe podłoże mechanizmu Java. Pierwszym podstawowym elementem jest JRE (Java Runtime Environment - środowisko uruchomieniowe Javy). JRE jest niezbędne do uruchamiania aplikacji Java na komputerze. A co to oznacza dla nas programistów? Oznacza nie mniej, nie więcej, a dokładnie tyle, że programy pisane w tym języku uruchamiane są nie "w komputerze", ale w pewnym środowisku działającym na komputerze. Dzięki temu jesteśmy pewni, że jeśli powstanie implementacja Wirtualnej Maszyny Java (JRE - w naszym przypadku) na jakąkolwiek maszynę, to będziemy mogli na tej maszynie uruchomić nasz program bez względu na to, czy będzie to: Atari ST, XBOX czy najnowsza wersja tostera marki "dla Ciebie dla Domu". Dzięki temu programy pisane w Javie będą mogły być uruchamiane nawet na sprzęcie, który pojawi się za 10-20 lat, o ile będzie istniała implementacja Wirtualnej Maszyny Java dla tych urządzeń.
Wykonywanie aplikacji języka Java poprzez JRE rozwijało się w następujących kierunkach:
Początkowo program mógł być interpretowany instrukcja po instrukcji (podobnie jak w językach skryptowych) jednak rozwiązanie to było bardzo niewydajne i powodowało, że programy napisane w języku Java działały bardzo wolno.
Aby zwiększyć wydajność programów napisanych w języku Java w nowoczesnych maszynach wirtualnych Java, zaimplementowano mechanizmy mające przyśpieszyć działanie programów. Jednym z nich jest technika JIT (Just In Time). Technologia Just In Time kompiluje kod bezpośrednio przed jego wykonaniem. Dzięki temu kompilowane są tylko i wyłącznie funkcje czy klasy, których używamy w naszym programie (a nie cały program). JIT w połączeniu z optymalizacją adaptacyjną pozwala działać programom napisanym w Java niemal tak szybko jak aplikacjom C/C++.
Poza JRE (niezbędnym użytkownikowi) istnieje inna popularna forma dystrybucji pakietu Java. JDK (Java Development Kit), zwana również SDK (Software Development Kit). To dystrybucja języka Java dla osób tworzących kod w języku Java. Poza środowiskiem uruchomieniowym zawiera między innymi: kompilator, dokumentację/pomoc i debugger. Poradnik jego instalacji został już opisany w sekcji wyżej.
Kod wykonywalny programu
Po napisaniu kodu źródłowego program kompilowany jest do bytecodu. Nie jest to jeszcze kod zrozumiały dla procesora w sposób bezpośredni, który pozwalałby nam na jego uruchomienie. Jest to jednak kod zapisany w określonym formacie, który może zostać poprawnie zinterpretowany przez Maszynę Wirtualną Java, przetłumaczony na kod wykonywalny i uruchomiony.
Zwalnianie pamięci w języku Java - Garbage Collector
W języku Java w tle, podczas działania naszego programu, działa mechanizm zwany Garbage Collector (zbieracz śmieci). Ma on na celu zwolnienie programisty z obowiązku dbania o zwalnianie pamięci w programie. Stosuje on szereg algorytmów mających na celu wyłapanie niepotrzebnych obiektów i usunięcie ich. Posiada to swoje wady i zalety.
Zaletą jest to, że programista nie musi pamiętać o zniszczeniu obiektu lub zwolnieniu pamięci. Mamy wolny czas, który normalnie poświęcilibyśmy na tworzenie destruktorów i czasochłonne myślenie nad tym, czy oby na pewno dobrze alokuję i zwalniam pamięć. Więcej nawet - istnieją problemy w których nie jesteśmy w stanie rozstrzygnąć, czy obiekt powinien zostać "już" zwolniony czy jeszcze powinien pozostać przy życiu. GC zrzuca z nas również ten ciężar.
Wadą jest to, że działanie Garbage Collectora zajmuje czas. Nigdy nie wiadomo kiedy Garbage Collector postanowi zadziałać i wyszukać oraz zwrócić do systemu nieużywaną już przez program pamięć. Przez to systemy czasu rzeczywistego pisane w Javie obwarowane są dodatkowymi restrykcjami, ponieważ działanie programu może być w każdej chwili wstrzymane na odśmiecanie.
Najprostsze mechanizmy działania Garbage Collectora to usuwanie obiektów, dla których ilość referencji wynosi zero (z takiego obiektu nie skorzystamy bo nie mamy się do niego jak odwołać, więc nie ma sensu trzymać go w pamięci) i odnajdywanie trójkącików (referencja A wskazuje na B, B wskazuje na C ale C znowu wskazuje na A), ale istnieją również bardziej złożone.
Ciekawostki
Istnieją właściwie dwa GC. Jeden uruchamiany jest często i zwalnia zmienne które nie są już potrzebne, a które zostały utworzone "niedawno". Np. użyte zmienne lokalne po opuszczeniu metody która ich używała. Drugi jest uruchamiany rzadziej, ale czyści dokładniej całą pamięć, jednak jego działanie może powodować zatrzymanie JVM do czasu zakończenia procesu odśmiecania (istnieją jednak implementacje JVM które nie posiadają tej wady). Powinieneś wiedzieć, że GC w "zasadzie działa", ale dla aplikacji bardzo intensywnie używających pamięć może zdarzyć się sytuacja, że GC nie zdąży z odśmieceniem nim nastąpi przepełnienie pamięci - w takim przypadku zostanie zrzucony wyjątek OutOfMemoryError i aplikacja w zasadzie przestanie działać. W takich programach warto używać przypisania do "null" - pomoże to GC łatwiej odnajdywać obiekty do usunięcia. Można również ręcznie zainicjować działanie GC poprzez użycie System.gc() - nie gwarantuje to, że wszystkie śmieci zostaną zwolnione, ale często może pomóc. Wgłębiając się w różne aspekty pamięci używanej przez JVM odnajdziesz obszar PermGen. Obszar PermGen nie jest odśmiecany (tak mówi doświadczenie) przez JVM, przechowuje się w nim między innymi informacje o klasach załadowanych przez ClassLoadera. Był taki problem z biblioteką javaassist, używanej przez kontener EJB3, który powodował ciągłe powiększanie obszaru zajmowanego PermGen, aż do katastrofy JVM. Do sterowania (w pewnym stopniu) GC mogą służyć parametry uruchomieniowe JVM.
Notka dla programistów C++
W Java nie ma zmiennych globalnych. Ponieważ w dobrym przybliżeniu wszystko jest klasą (dokładnie rzecz ujmując może być klasą), więc zmienna globalna nie istnieje (każda zmienna jest składową jakiejś klasy lub zmienną lokalną).
Wszystkie klasy są pochodnymi od jednej wspólnej klasy Object.
W Java nie ma wielokrotnego dziedziczenia. W Java występuje za to mechanizm interfejsów. Jedna klasa może implementować wiele interfejsów.
Brak preprocesora. Nie jest potrzebny ponieważ wszystkim może zająć się Wirtualna Maszyna Java.
Nie ma plików nagłówkowych. Program podzielony jest na pakiety.
Brak typedef - tworzenie alternatywnych nazw dla istniejących typów nie jest wspierane.
Brak możliwości przeciążania operatorów.
Operator zakresu :: jest zastąpiony znakiem kropki.
W języku Java nie istnieje możliwość przekazania domyślnej wartości, ani listy inicjalizującej w C++.
Brak destruktorów i konieczności pamiętania o zwalnianiu pamięci. Działa garbage collector, który robi to za nas.
Przy przekazywaniu argumentów dominuje referencja - wyjątkami są typy proste przekazywane przez wartość.
W Javie łańcuchy znaków są obiektami klasy java.lang.String.
Nauka programowania w języku Java
Naukę programowania można podzielić na pewne etapy. Pierwszy to poznanie struktur języka takich jak: pętle, warunki, operatory, podstawowe wyrażenia i składnia. Nie da się w tym czasie uniknąć osobnego działu, jakim jest korzystanie z bibliotek dostępnych w języku. Choćby po to, by wyświetlić coś na ekranie lub pobrać wiadomość od użytkownika. Te dwa elementy przeplatają się w początkowych etapach nauki języka. Później przychodzi czas na szczegóły związane z semantyką oraz składnią kodu, niuansami, dzięki którym można tworzyć optymalny kod i pisać kod sprytniej i wydajniej.
Poza nauką języka programowania trzeba poznać paradygmaty programowania jako takiego czyli przyjęte, obowiązujące lub zalecane reguły pisania programu, niezależne od tego w jakim języku programowania (wysokiego poziomu) piszemy. Jest to tak zwany dział "inżynierii oprogramowania", którym tutaj nie będziemy się zajmować.