Java

obiektowy język programowania

Java (wym. dżawa[3]) – współbieżny, oparty na klasach, obiektowy język programowania ogólnego zastosowania[4]. Został stworzony przez grupę roboczą pod kierunkiem Jamesa Goslinga z firmy Sun Microsystems. Java jest językiem tworzenia programów źródłowych kompilowanych do kodu bajtowego, czyli postaci wykonywanej przez maszynę wirtualną. Język cechuje się silnym typowaniem. Jego podstawowe koncepcje zostały przejęte z języka Smalltalk (maszyna wirtualna, zarządzanie pamięcią) oraz z języka C++ (duża część składni i słów kluczowych).

Java
logo
Pojawienie się

1995

Paradygmat

Wieloparadygmatowy (obiektowy, strukturalny, imperatywny, funkcyjny)

Implementacje

OpenJDK, HotSpot

Twórca

James Gosling

Licencja

GNU General Public License

Platforma sprzętowa

wieloplatformowy

Platforma systemowa

Windows x86/x64/IA64 Linux x86/x64/IA64, Solaris[1][2]

Strona internetowa

Społeczność programistów określana jest jako Java User Group[5].

Oracle regularnie wydaje nowe wersje Javy co pół roku[6]. We wrześniu 2021 Oracle ogłosiło skrócenie okresu wydawania wersji LTS z trzyletniego na dwuletni[6].

Historia edytuj

James Gosling, Mike Sheridan i Patrick Naughton zainicjowali projekt języka Java w czerwcu 1991 r.[7] Java została pierwotnie zaprojektowana dla telewizji interaktywnej, ale była wówczas zbyt zaawansowana dla branży cyfrowej telewizji kablowej[8]. Gosling zaprojektował Javę ze składnią w stylu C/C++, którą programiści systemów i aplikacji mogliby uznać za znajomą.

Firma Sun Microsystems wydała pierwszą publiczną implementację jako Java 1.0 w 1996 roku[9]. Zapewniał funkcjonalność WORA (ang. Write Once, Run Anywhere), zapewniającą darmowe środowisko uruchomieniowe na popularnych platformach. Dość bezpieczny i wyposażony w konfigurowalne zabezpieczenia pozwalał na ograniczenia dostępu do sieci i plików. Popularne przeglądarki internetowe wkrótce włączyły możliwość uruchamiania apletów Java na stronach internetowych, a Java szybko stała się popularna. Kompilator Java 1.0 został ponownie napisany w Javie przez Arthura van Hoffa w celu ścisłej zgodności ze specyfikacją języka Java 1.0.

Wraz z pojawieniem się Java 2 (wydanej początkowo jako J2SE 1.2 w grudniu 1998 - 1999), nowe wersje miały wiele konfiguracji zbudowanych dla różnych typów platform. J2EE zawierała technologie i interfejsy API dla aplikacji korporacyjnych, które zwykle działają w środowiskach serwerowych, natomiast J2ME zawierało interfejsy API zoptymalizowane pod kątem aplikacji mobilnych. Wersja desktopowa została przemianowana na J2SE. W 2006 w celach marketingowych firma Sun zmieniła nazwy nowych wersji J2 na odpowiednio Java EE, Java ME i Java SE.

Główne koncepcje edytuj

Autorzy języka Java określili kilkanaście kluczowych koncepcji swojego języka. Najważniejsze z nich to:

Obiektowość edytuj

W przeciwieństwie do wieloparadygmatowego języka C++, Java jest silnie ukierunkowana na programowanie obiektowe. Wyjątkiem od całkowitej obiektowości (jak np. w Smalltalku) są typy proste (int, float itp.), inaczej nazywane typami prymitywnymi. Należy jednak pamiętać, że również i one mają swoje odzwierciedlenie obiektowe w przypadku potrzeby użycia danego sposobu zapisu w typach generycznych. Metody i klasy mogą być poprzedzone tzw. adnotacjami[10].

// oznacza komentarz
// w tej postaci to obiekt reprezentujący kolorowy punkt
public class Figura
{
    // operacje (metody)
    public float obliczPole()
    {
        return 0;
    }

    public float obliczObwód()
    {
        return 0;
    }

    public void wyświetl() { ... }

    // właściwości (atrybuty/pola)
    protected float środekX;
    protected float środekY;
    protected int kolor; // tak naprawdę do przechowywania(tworzenia)
                       // koloru używa się zazwyczaj obiektu java.awt.Color
    ...
}
Jak widać z powyższego, statyczne typowanie oznacza, że każda wprowadzana zmienna czy pole musi mieć przypisany typ przechowywanych w niej danych (float oznacza typ zmiennoprzecinkowy), a każda metoda musi deklarować, jakiego typu dane zwraca (lub void, jeśli nic nie zwraca). Uwaga: od Javy w wersji 10 można stosować inferencję typów za pomocą słowa kluczowego var. Z przykładu widać też, że w nazwach zmiennych i metod można używać polskich liter – to zasługa wbudowanej obsługi kodowania Unicode. Pokazany sposób nazywania zmiennych i metod (tzw. camel case polegający na pisaniu słów bez spacji, a z kapitalizowaniem drugiego i następnych słów składowych) jest nieobowiązkowy, ale jest jedną z uznanych dobrych praktyk programowania w Javie.

Dziedziczenie edytuj

W Javie wszystkie obiekty są instancjami klasy Object, z której dziedziczą podstawowe zachowania i właściwości. Dzięki temu wszystkie mają wspólny podzbiór podstawowych możliwości, takich jak ich: identyfikacja, porównywanie, kopiowanie, niszczenie czy wsparcie dla programowania współbieżnego.

// „extends” oznacza dziedziczenie po klasie Figura pól: środekX, środekY i kolor
// oraz metod: obliczPole, obliczObwód i wyświetl
public class Kwadrat extends Figura
{
    // dodatkowe atrybuty
    private float wierzchołekX;
    private float wierzchołekY;
    private float długośćBoku;

    // „przesłaniamy” operacje rodzica, dzięki czemu dla każdej 
    // zdefiniowanej Figury można policzyć pole czy obwód
    @Override
    public float obliczPole()
    {
        return długośćBoku * długośćBoku;
    }
    ...
}

Choć C++ udostępniał dziedziczenie wielokrotne, projektanci Javy odeszli od tego pomysłu. Java umożliwia jedynie dziedziczenie po jednej klasie, a więc wyłącznie jedna klasa może przekazać swoje właściwości i operacje jako podstawę do rozszerzania ich o dodatkowe możliwości. Dzięki temu wyeliminowano możliwość konfliktów między właściwościami przekazywanymi przez klasy nadrzędne.

By zrekompensować spadek elastyczności wynikający z pojedynczego dziedziczenia wprowadzono interfejsy oraz podklasy umożliwiające wielokrotne dziedziczenie implementacji. Pozwalają one nazwać pewien określony zbiór operacji, dzięki czemu można określić, że dany obiekt, któremu przypisano dany interfejs (implementujący go), umożliwia wykonanie owego zestawu operacji.

Niezależność od architektury edytuj

Tę właściwość Java ma dzięki temu, że kod źródłowy programów pisanych w Javie kompiluje się do kodu pośredniego. Powstały kod jest niezależny od systemu operacyjnego i procesora, a wykonuje go tzw. wirtualna maszyna Javy, która (między innymi) tłumaczy kod uniwersalny na kod dostosowany do specyfiki konkretnego systemu operacyjnego i procesora. W tej chwili wirtualna maszyna Javy jest już dostępna dla większości systemów operacyjnych i procesorów.

Jednak z uwagi na to, że kod pośredni jest interpretowany, taki program jest wolniejszy niż kompilowany do kodu maszynowego. Z tego względu maszynę wirtualną często uzupełnia się o kompilator JIT. Istnieją również niezależne od Suna kompilatory Javy – przykładem podprojekt GCC o nazwie GCJ.

Sieciowość i obsługa programowania rozproszonego edytuj

Dzięki wykorzystaniu reguł obiektowości, Java nie widzi różnicy między danymi płynącymi z pliku lokalnego a danymi z pliku dostępnego przez HTTP czy FTP. Biblioteki Javy udostępniają wyspecjalizowane funkcje umożliwiające programowanie rozproszone – zarówno między aplikacjami Javy (RMI), jak i między aplikacją Javy a aplikacjami napisanymi w innych językach (CORBA, usługi sieciowe). Inne biblioteki udostępniają możliwość pisania aplikacji uruchamianych w przeglądarkach internetowych (aplety Javy) oraz aplikacji działających ciągle po stronie serwera (serwlety)[11][12].

Niezawodność i bezpieczeństwo edytuj

W zamierzeniu Java miała zastąpić C++ – obiektowego następcę języka C. Jej projektanci zaczęli od rozpoznania tych cech języka C++, które są przyczyną największej liczby błędów programistycznych, by stworzyć język prosty w użyciu, bezpieczny i niezawodny.

O ile po dziesięciu odsłonach Javy jej prostota jest dyskusyjna, o tyle język faktycznie robi dużo, by utrudnić programiście popełnienie błędu. Przede wszystkim Java ma system wyjątków, czyli sytuacji, gdy kod programu natrafia na nieprzewidywane trudności, takie jak np.:

  • operacje na elemencie poza zadeklarowaną granicą tablicy lub elemencie pustym,
  • czytanie z niedostępnego pliku lub nieprawidłowego adresu URL,
  • podanie nieprawidłowych danych przez użytkownika.

W Javie obsługa wyjątków jest obowiązkowa (programista ma możliwość wywołania wyjątku throw, jednak musi dodać do danej metody deklarację throws lub otoczyć kod narażony na wystąpienie wyjątku blokiem try{...} catch{...}; nie jest to wymagane w przypadku obiektów wyjątków dziedziczących po klasie RuntimeException lub Error)[13]. Przy tym obiekty wchodzące w skład pakietu standardowego Javy implementują wyjątki w każdym miejscu kodu, którego wykonanie jest niepewne ze względu na okoliczności zewnętrzne.

Sama obsługa wyjątków polega na napisaniu kodu, który wykona się w odpowiedzi na taką sytuację nadzwyczajną. Może to być np. podstawienie wartości domyślnej przy natrafieniu na nieprawidłową wartość parametru, zaniechanie danej akcji i powrót do stanu stabilnego czy choćby zapisanie pracy przed wyjściem. W sytuacji wyjątkowej program przerywa normalne wykonanie i tworzy specjalny obiekt wyjątku odpowiedniej klasy, który „wyrzuca” dalszą część działania z normalnego biegu programu. Następnie zdefiniowany przez użytkownika kod „łapie” ten obiekt wyjątku i podejmuje odpowiednie działanie. Działanie może być dwojakiego typu: wspomniane wyżej środki zaradcze lub pominięcie części działania aplikacji dalej, do bloku programu, który nakazał wykonanie wadliwej operacji. Takie podawanie sobie wyjątku może być wieloetapowe i jeśli skończy się w bloku głównym programu powoduje jego przerwanie i ogłoszenie błędu krytycznego.

Oprócz systemu wyjątków Java od wersji 1.4 ma dwa inne systemy wspomagające pisanie niezawodnych programów: logowanie i asercje. Pierwsze pozwalają na zapisanie w plikach dziennika przebiegu działania programu, z dodatkową możliwością filtrowania zawartości, określenia poziomu logowanych błędów itp. Drugie rozwiązanie pozwala na upewnienie się, że pewne założenia co do określonych wyrażeń (np. że liczba, z której wyciągamy pierwiastek jest nieujemna) są prawdziwe. Asercje są o tyle ciekawe, że działają tylko z odpowiednią opcją wykonania programu, dzięki czemu programista może sprawdzić działanie programu, a później bez wysiłku spowodować pominięcie testowej części kodu po prostu przez ominięcie tej opcji. Od wersji Javy 7 istnieje również klasa Objects, która przy użyciu pomocniczych metod umożliwia szerszą walidację typów, takich jak sprawdzenie, czy zmienna nie jest tzw. nullem przed przekazaniem jej do dalszej części programu.

W Java 17 LTS pojawiły się m.in. ulepszenia związane z obsługą pamięci, zwiększenie wydajności oraz nowe narzędzia do monitorowania i zarządzania systemem.[14] W wersji 21 LTS pojawiły się usprawnienia w obszarze obsługi strumieni, wprowadzenie nowych bibliotek do pracy z danymi oraz ulepszenia związane z wydajnością i bezpieczeństwem.[15]

Krytyka i kontrowersje edytuj

Język Java, pomimo swoich wielu zalet, ma wiele wad, w tym takie, które wzbudzają liczne kontrowersje:

  • Najczęściej wymienianą wadą języka Java jest to, że programy pisane w Javie wykonują się wolniej niż programy pisane w językach natywnie kompilowanych (np. C++). Zarzut ten odnosi się szczególnie do starych wersji Javy, kiedy zaawansowane mechanizmy takie jak JIT albo współbieżne odśmiecanie pamięci nie były dostępne. Z uwagi jednak na zmiany w kompilatorze JIT, od wersji 11 Java powinna wykonywać się szybciej[16].
  • Javie zarzuca się, że niezbyt dobrze nadaje się do zastosowań czasu rzeczywistego. Głównym problemem jest brak przewidywalności wydajności oraz nieoczekiwane przestoje powodowane działaniem odśmiecacza. W nowych wersjach Javy ten drugi problem został radykalnie ograniczony, jednak nadal do zastosowań czasu rzeczywistego lepiej stosować języki natywnie kompilowane.
  • Często Javie zarzucane jest to, że ma mniejszą funkcjonalność niż np. C++, co ogranicza programistę. Jako przykład przywołuje się czasami fakt, że aby uruchomić niewielki program, trzeba napisać dłuższy kod programu. Niektórzy jednak zwracają uwagę, że również język C++ nie ma wielu elementów, które można znaleźć w Javie, jak np. klasy anonimowe, odśmiecacz pamięci, system pakietów, dynamiczne ładowanie klas czy reflection API.
  • Java wymusza konwersję typów prostych (np. int) na odpowiadający typ referencyjny (np. java.lang.Integer) przy pracy z kolekcjami, co może mieć negatywny wpływ na wydajność w specyficznych sytuacjach, otwiera kod na możliwe niepożądane efekty (typ referencyjny może być nullem, kiedy typ prymitywny - nie) i zmniejsza czytelność programu. Typy generyczne, wprowadzone w wersji 5, oraz tzw. autoboxing, czyli automatyczna konwersja pomiędzy typami prostymi i ich obiektowymi odpowiednikami usunęły problem czytelności. Programista może już także wybrać, jakim algorytmem zostanie zaimplementowana dana kolekcja (np. lista może być zaimplementowana jako tablica o zmiennym rozmiarze, drzewo, albo lista jednokierunkowa), co pozwala na poprawienie wydajności.

Dystrybucje języka Java edytuj

Pakiety edytuj

Java nie jest monolitem, lecz składa się z szeregu klas definiujących obiekty różnego typu. Dla przejrzystości klasy te pogrupowane są w hierarchicznie ułożone pakiety, które system operacyjny widzi jako katalogi. Każdy pakiet grupuje klasy związane z pewnym szerokim zakresem zastosowań języka np. java.io (klasy wejścia-wyjścia), java.util.prefs (klasy użytkowe do obsługi preferencji) czy java.awt (system obsługi trybu graficznego). Hierarchię klas oddają nazwy pakietów, które skonstruowane są podobnie jak ścieżki dostępu do plików. Na przykład klasa Preferences znajdująca się w pakiecie java.util.prefs ma pełną nazwę: java.util.prefs.Preferences, co oznacza:

  • java – pakiet należy do zestawu standardowych pakietów Javy,
  • util – to różnego typu klasy użytkowe (pomocnicze) głównie organizujące obsługę różnego typu struktur danych,
  • prefs – system obsługi preferencji w sposób niezależny od platformy, w którym preferencje systemowe i użytkownika są składowane w postaci hierarchicznego rejestru,
  • Preferences – konkretna nazwa klasy.

Dzięki takiemu systemowi nazwy klas są niepowtarzalne, co pozwala uniknąć niejednoznaczności (np. czy chodzi o klasę List implementującą strukturę listy danych czy o List implementującą graficzną listę wyświetlaną w okienku).

Wszystkie klasy pisane przez programistów niezależnych powinny być umieszczane w innych hierarchiach. Firma Sun często zaleca, by w nazewnictwie klas niestandardowych przed właściwą nazwą pakietu stosować odwróconą nazwę domeny internetowej autora pakietu. Na przykład narzędzie Ant znajduje się w pakiecie org.apache.ant, co zapobiega konfliktom nazw z pakietami innych autorów, którzy również chcieliby nazwać swój pakiet Ant.

Domyślnie klasy pakietu nie są możliwe do użycia poza nim. Stąd nie występują konflikty nazw klas przy imporcie różnych pakietów. Klasa pakietu staje się publiczną przy użyciu modyfikatora dostępu public.

JRE a JDK edytuj

Pakiety z hierarchii java i javax (dodatki wprowadzone w późniejszych wersjach) należą do podstawowego zestawu klas rozprowadzanych jako Java. Zestaw ten jest dostępny w dwóch wersjach: JRE (Java Runtime Environment) – udostępnia kod bajtowy wszystkich klas standardowych i wirtualną maszynę do ich uruchamiania, zaś JDK (Java Development Kit) dodatkowo udostępnia źródła tych klas oraz dodatkowe narzędzia takie jak kompilator, kompresor czy debugger. Podział ten wprowadzono dlatego, że użytkownik Javy do uruchamiania programów potrzebuje tylko JRE, natomiast do programowania działających aplikacji potrzeba już JDK.

Implementacje Javy edytuj

 
Kolumna wierszy w Java script

Potocznie pod nazwą Java rozumie się nie tylko język programowania, ale także całe środowisko (JDK) stworzone przez firmę Sun, a którego obecnym właścicielem jest Oracle Corporation. Z tego uogólnienia wynikają pewne nieścisłości, jak np. to, że Java jest niezależna od architektury – nie jest to jednak cecha samego języka, a mechanizmu wirtualnej maszyny wykorzystywanego tej w standardowej implementacji.

Swoją własną implementację JDK, certyfikowaną w ramach Java Community Process, tworzy na przykład IBM. Z uwagi jednak na zmiany w umowie, wprowadzone przez Oracle, od Javy 9 nie jest możliwe pobranie środowiska bezpośrednio ze strony Oracle bez zarejestrowanej organizacji[17]. Krok ten doprowadził do otwarcia wielu projektów, udostępniających pakiet JDK bez potrzeby rejestracji w systemie Oracle, takich jak Eclipse Temurin od Adoptium, Amazon Corretto, czy Azul Zulu. Nadal można również pobrać niektóre wersje Javy tworzone przez Oracle w ramach projektu OpenJDK.

Inne podejście prezentuje projekt GCJ, który pozwala kompilować programy w Javie bezpośrednio do kodu maszynowego.

JavaFX edytuj

W 2007 roku firma Sun ogłosiła swe plany wprowadzenia nowego języka skryptowego o nazwie JavaFX Script. Cele przyświecające temu językowi są podobne do tych, które zawsze towarzyszyły Javie:

Język JavaFX Script nie jest zupełnie nowym produktem, lecz rozszerzeniem wcześniejszej Javy. Nowe aplikacje będą funkcjonować bez żadnych modyfikacji na każdej maszynie wirtualnej Javy.

Tym posunięciem firma Sun stara się dorównać konkurencji, która promuje takie rozwiązania jak:

Zobacz też edytuj

Przypisy edytuj

  1. http://www.oracle.com/technetwork/java/javase/system-configurations-135212.html Supported System Configurations for non-Itanium platforms → Lista implementacji poza architekturą Itanium.
  2. http://web.archive.org/web/20110125024639/http://www.oracle.com/technetwork/java/javase/downloads/default-177153.html About 1.6.0_22 (6u22) for the Itanium® architecture → Uwagi do wydania 1.6.0_22 (6u22) dla architektury Itanium.
  3.   Java [w:] Słownik języka polskiego PWN [online] [dostęp 2022-09-02].
  4. James Gosling, Bill Joy, Guy Steele, Gilad Bracha, Alex Buckley: The Java ® Language Specification Java SE 8 Edition. 2015-02-13. [dostęp 2018-04-10]. (ang.).
  5. Java User Groups - Dev.java, Dev.java: The Destination for Java Developers [dostęp 2023-02-10] (ang.).
  6. a b Donald Smith: Moving the JDK to a Two Year LTS Cadence. [w:] blogs.oracle.com [on-line]. Oracle, 2021-09-14. [dostęp 2024-02-20]. (ang.).
  7. Java Technology: The Early Years, web.archive.org, 20 kwietnia 2005 [dostęp 2020-08-11] [zarchiwizowane z adresu 2005-04-20].
  8. The History of Java Technology, web.archive.org, 10 lutego 2010 [dostęp 2020-08-11] [zarchiwizowane z adresu 2010-02-10].
  9. JAVASOFT SHIPS JAVA 1.0, web.archive.org, 10 marca 2007 [dostęp 2020-08-11] [zarchiwizowane z adresu 2007-03-10].
  10. Manoj Debnath, Getting Started with Java Annotations, Developer.com, 11 listopada 2015 [dostęp 2023-02-10] (ang.).
  11. 4programmers.net: Java [dostęp 2016-11-15].
  12. Edu.pjwstk.edu.pl: RMI – programowanie rozproszone [1].
  13. Oracle: The Java™ Tutorials: Exceptions: Unchecked Exceptions – The Controversy.
  14. Dariusz Wawer, Java 17 features: A comparison between versions 8 and 17, Pretius, 7 grudnia 2022 [dostęp 2024-02-20] (ang.).
  15. Arkadiusz Rosłoniec, Java 21 features: A detailed look at the most important changes in the new LTS release, Pretius, 1 lutego 2024 [dostęp 2024-02-20] (ang.).
  16. How much faster is Java 11?, OptaPlanner [dostęp 2021-07-25] (ang.).
  17. Tim Anderson, 'Java 9, it did break some things,' Oracle bod admits to devs still clinging to version 8, www.theregister.com [dostęp 2021-07-25] (ang.).

Linki zewnętrzne edytuj