jshell czyli Witaj Świecie w Javie po nowemu

Piotr Przybył 2 lipca 2019
 

W tym wpisie dowiesz się, jak napisać “Witaj, Świecie!” w Javie bez kompilacji.

Java na tle innych języków

Istnieje wiele osi podziału języków programowania. Przykładowe to: obiektowość (lub jej brak), różne stopnie wsparcia paradygmatu funkcyjnego, typizacja silna lub słaba, statyczna lub dynamiczna czy łatwość nauki. Istnieje wreszcie możliwość podzielenia języków programowania na takie, które wymagają kompilacji w celu późniejszego uruchomienia, jak i tzw. “języki skryptowe”, gdzie kompilacja nie jest wymagana.

Miłym zaskoczeniem dla wielu młodych adeptów Javy jest fakt, że od wersji 9 Java nie wymaga kompilacji w każdej możliwej sytuacji, w związku z tym stała się językiem jeszcze łatwiejszym do nauki.

Jak to do tej pory było

Aż do Javy 8 włącznie, żeby wypisać coś w CLI (ang. Command Line Interface, zwanym często terminalem lub powłoką), trzeba było

  • najpierw stworzyć plik tekstowy z rozszerzeniem .java, który umożliwiał (poprzez właściwe wykorzystanie składni języka) napisanie kodu wypisującego “Witaj, Świecie!”,
  • następnie dokonać tzw. kompilacji, czyli wywołać narzędzie javac na pliku .java w celu utworzenia pliku z rozszerzeniem .class, który to plik zawiera instrukcje w tzw. kodzie bajtowym (ang. byte code) zrozumiałym dla Wirtualnej Maszyny Javy (ang. Java Virtual Machine, JVM),
  • wreszcie należało wywołać narzędzie java (z podaniem nazwy pliku .class jako parametru), żeby program uruchomić.

W porównaniu do innych języków, np. Pythona, PHP, JavaScriptu, HTML, itp. stanowi to pewne utrudnienie na początek. Zamiast wykonania jednego kroku w celu wywołania programu (np. odświeżenia pliku HTML czy .js w przeglądarce), trzeba było wykonać ich więcej.

Oczywiście istnieją narzędzia umożliwiające wykonanie wszystkich tych kroków za młodego adepta, jak zintegrowane środowisko programistyczne (ang. Integrated Development Environment, IDE), np. Eclipse, IDEA, NetBeans, itp. lub narzędzia służące do automatyzacji procesu budowania bardziej skomplikowanych aplikacji, np. Gradle lub Maven. Oczywiście, można było także we własnym zakresie napisać prosty skrypt wywołujący polecenia javac i java.

Na szczęście od Javy 9 jest to już dużo łatwiejsze. Co prawda “pod maską” proces kompilacji zachodzi nadal, jednak napisanie i uruchomienie prostego programu typu “Witaj, Świecie!” nie wymaga już tak wiele zachodu, nie trzeba uruchamiać kompilatora własnoręcznie.

Witaj, Świecie!

Poniżej znajduje się najpopularniejszy chyba program napisany w Javie:

public class WitajŚwiecie {
    public static void main(String[] args) {
        System.out.println("Witaj, Świecie!");
    }
}

Zgodnie z obowiązującymi w Javie zasadami, jeśli plik z kodem źródłowym (czyli taki z rozszerzeniem .java) zawiera klasę publiczną WitajŚwiecie (możemy to poznać bo obecności słów kluczowych public class), to plik taki musi nazywać się WitajŚwiecie.java. (Pamiętajmy, że nazwy klas, metod, pól w Javie mogą zawierać polskie znaki. I choć z różnych względów nie zawsze jest to najlepsza praktyka, nic nie stoi na przeszkodzie, by przywitać świat Javy w języku ojczystym.)

“Stary” sposób

Skoro mamy już zapisany kod źródłowy programu w pliku WitajŚwiecie.java, pora dokonać kompilacji. W tym celu należy w CLI (np. bash w Linuksie lub cmd w Windowsie) przejść do katalogu, w którym mamy zapisany ten plik (wykorzystując w tym celu polecenie cd) i wywołać:

javac WitajŚwiecie.java

(Pamiętaj, że wymagane jest także podanie rozszerzenia pliku.)

Jeśli wszystko przebiegło jak należy, kompilator jest zainstalowany poprawnie i nie zgłosił on żadnych błędów, to w katalogu bieżącym powinien pojawić się plik o nazwie WitajŚwiecie.class.

To połowie drogi, teraz trzeba nasz program uruchomić. Tym razem w CLI należy wywołać (bez zmieniania katalogu) polecenie java i “nakarmić” je plikiem .class uzyskanym w poprzednim kroku.

java WitajŚwiecie

Trzeba zauważyć, że tym razem nie podajemy rozszerzenia pliku, czyli nie wpisujemy na końcu .class!

Jeśli Java jest zainstalowana Javę, program powienien wypisać w terminalu następującą linię:

Witaj, Świecie!

Zmiany, zmiany, zmiany…

Gdy trzeba zmodyfikować nasz program należy ponownie wykonać wszystkie powyższe kroki. Jeśli chcemy na przykład, żeby program wypisywał Witaj, Świecie Javy!, to wtedy należy:

  • zmienić zawartość pliku WitajŚwiecie.java (pamiętajmy o zapisaniu zmian w pliku ;-))
  • ponownie wywołać javac WitajŚwiecie.java
  • na koniec uruchomić java WitajŚwiecie

I tak za każdym razem… trochę męczące, prawda?

Na szczęście da się to uprościć, jeśli mamy zainstalowaną Javę 9 lub nowszą (np. 11, 12, itp.).

“Nowy” sposób

Mając zainstalowaną Javę 9 lub nowszą można pominąć etap jawnego wywołania kompilatora i wywołać polecenie java “karmiąc” je bezpośrednio plikiem z kodem źródłowym (czyli tym z rozszerzeniem .java). Pomijamy krok z tworzeniem pliku .class z pliku .java, czyli kompilację.

Uwaga: przed wykonaniem tego ćwiczenia trzeba wcześniej usunąć z katalogu plik WitajŚwiecie.class.

Podobnie jak poprzednio, należy mieć otwarte CLI w katalogu w którym znajduje się plik WitajŚwiecie.java. Wówczas wywołujemy polecenie:

java WitajŚwiecie.java

Zauważmy, że tym razem wykonujemy to polecenie dla pliku z rozszerzeniem .java podanym jawnie. Jeśli wszystko przebiega sprawnie, powinniśmy na ekranie zobaczyć wyświetlony napis:

Witaj, Świecie!

(Lub to, co aktualnie ten plik zawiera, jeśli zmieniliśmy zawartość pliku WitajŚwiecie.java.) Jeśli widzisz na ekranie komunikat o treści:

error: class found on application class path: WitajŚwiecie

oznacza to, że w katalogu nadal znajduje się plik .class i należy go usunąć.

Jak pokazuje powyższe ćwiczenie, z procesu “napisz, skompiluj i uruchom program” udało nam się wyeliminować jeden krok, czyli “skompiluj”.

Ale to nie koniec zmian na lepsze.

jshell, czyli Java w końcu ma terminal

Do tej pory, żeby przetestować jakiś prosty (a w zasadzie każdy) sposób na zrobienie czegoś w Javie, trzeba było utworzyć jakiś plik .java, skompilować go do .class, następnie uruchomić .class (zwykle spakowany z innymi w plik JAR). De facto istniały dwa standardowe podejścia. Pierwsze, najbardziej podstawowe, zakładało utworzenie klasy publicznej zawierającej metodę main (jak powyższe przykłady). Drugie, nieco bardziej zaawansowane, polegało na utworzeniu pliku z testem jednostkowym i wywołanie tego testu (np. metod z adnotacją @Test dla JUnita).

Java nie posiadała czegoś w rodzaju “konsoli Javy”. Jeśli znasz inne języki, np. Python czy PHP, zapewne wiesz, że można je uruchomić w CLI (terminalu), wpisać linię, która zawiera jakąś instrukcję poprawną dla tego języka, następnie linia ta jest wczytywana przez “konsolę”, wykonywana, następuje wypisanie rezultatu i zapętlenie do początku. Jest to przykład narzędzia REPL, akronim ten tworzą angielskie słowa read (wczytaj), evaluate (wykonaj), print (wypisz), loop (zapętlij).

Brak było takiego oficjalnego narzędzia dla Javy, choć istniały dla innych języków obecnych na JVMie, np. w języku Scala. Od Javy w wersji 9 narzędzie to już istnieje, nazywa się jshell i działa świetnie.

Jeśli zatem chcesz przećwiczyć różne sposoby wypisywania czegoś na konsolę, nie ma już nawet potrzeby tworzenia pliku WitajŚwiecie.java i jego uruchamiania!

Wystarczy, że w CLI, w dowolnym katalogu, uruchomisz polecenie jshell. Jeśli jest ono zainstalowane poprawnie, zobaczysz następujący komunikat powitalny:

jshell
|  Welcome to JShell -- Version 12.0.1
|  For an introduction type: /help intro

(Zgłaszana wersja może się różnić w zależności od tego, którą wersję Javy masz zainstalowaną.) W następnej linii możemy wpisać poprawną instrukcję Javy, nie trzeba w tym celu tworzyć klas ani metod. Wystarczy za jshell> wpisać interesującą nas instrukcję, np.

jshell> System.out.println("Witaj, Świecie! Pozdrowienia z jshella!");

Wówczas na ekranie powinniśmy zobaczyć:

Witaj, Świecie! Pozdrowienia z jshella!

Nic nie stoi na przeszkodzie, żeby w tym miejscu zacząć wpisywać kolejne instrukcje. Każda kolejna instrukcja może korzystać z wyników poprzednich instrukcji. Przykładowo:

jshell> int a = 10;
a ==> 10

jshell> int b = 32;
b ==> 32

jshell> a + b;
$5 ==> 42

Aby zakończyć pracę w jshellu, należy wykonać instrukcję /exit. (Nie jest to instrukcja Javy, jest to jedno z poleceń obecnych wyłącznie w jshellu.)

jshell> /exit
|  Goodbye

Jeśli chcesz poznać inne możliwości jshella, dobrym pomysłem może być wywołanie /help, wypisze to inne możliwe polecenia, opcje, itd.

Jeżeli nie chcesz za każdym razem wpisywać wszystkich poleceń dla jshella od początku, możesz zapisać instrukcje w pliku i zlecić jshellowi ich wykonianie.

Przykładowo, możemy w pliku wyliczanka.jsh zapisać następującą treść:

System.out.println("Raz")
System.out.println("Dwa")
System.out.println("Trzy")
System.out.println("Kryjesz TY!")
/exit

W tym miejscu warto zauważyć, że:

  • w jshellu instrukcji nie trzeba kończyć średnikiem jak w pliku .java
  • jeśli chcemy zakończyć działanie skryptu, w ostatniej linii można wpisać /exit

Następnie w CLI należy wykonać polecenie:

jshell wyliczanka.jsh

Powinno to uruchomić jshell i dać taki rezultat, jak poniżej:

jshell wyliczanka.jsh 
Raz
Dwa
Trzy
Kryjesz TY!

JavaScript?!? Panie, co Pan??

Wiele osób zna zapewne krążące po Internecie dowcipy (dość suche prawdę mówiąc), że “poszukujemy programisty Javy w wersji Script”…

Z racji podobieństwa nazw i faktu, że zarówno Java i JavaScript są językami programowania, wyrosło wiele nieporozumień. Programiści obu tych technologii czasem zżymają się, gdy ktoś uzna, że znając jedną, automatycznie są w stanie tworzyć i w drugiej.

Jednak co ciekawe, teraz można w Javie pisać… skrypty. ;-) Jest to podejście nieco humorystyczne i cokolwiek naciągane, ale jednak prawdziwe. (Oczywiście, “skrypty” te są pisane w Javie, nie w JavaScripcie.)

Poniższy przykład dotyczy systemów operacyjnych Linux, Unix i Mac. Do jego zrozumienia trzeba zapoznać się z koncepcją tzw. shebang, np. w Wikipedii.

Skracając wprowadzenie do minimum: poprzez dopisanie na początku pierwszego przykładu (WitajŚwiecie.java) linii, która zawiera !#/pełną/ścieżkę/do/polecenia/java oraz ustawienie na tym pliku flagi oznaczającej plik wykonywalny, możemy w ten sposób utworzyć skrypt, który jest napisany nie w Bashu czy Pythonie, tylko w Javie. Jak by nie kombinować, daje to Java script :-D

Aby zrobić to w systemie Linux lub Mac, należy wykonać poniższe kroki:

Krok 1: najpierw poznaj pełną ścieżkę do polecenia java zainstalowanego u Ciebie, wykorzystując polecenie which. W moim przypadku wywołanie which java daje następujący rezultat.

which java
/home/piotrprz/.sdkman/candidates/java/current/bin/java

Krok 2: następnie utwórz plik o nazwie WitajJava.script i następującej treści (wykorzystując poznaną krok wcześniej pełną ścieżkę do polecenia Java):

#!/home/piotrprz/.sdkman/candidates/java/current/bin/java

public class WitajJava {
    public static void main(String[] args) {
        System.out.println("Witaj, tu skrypt napisany w Javie!");
    }
}

Krok 3: teraz trzeba ustawić ten plik jako plik wykonywalny, wykorzystajmy do tego polecenie chmod w postaci:

chmod a+x WitajJava.script

Krok 4: nic nie stoi na przeszkodzie, by uruchomić teraz ów skrypt w CLI w sposób podany poniżej:

./WitajJava.script

Jeśli wszystkie kroki zostały wykonane poprawnie, naszym oczom powinien ukazać się napis:

Witaj, tu skrypt napisany w Javie!

Gratulacje, to Twój pierwszy skrypt napisany w Javie! ;-)

Czy to wszystko?

Oczywiście, udało nam się jedynie zarysować nowe możliwości narzędzi java oraz jshell. Mają one dużo więcej opcji, np. jshell umożliwia także podanie ścieżki klas (ang. class path), zapisu historii do pliku, itd.

Podsumowanie

  • Do Javy 8 w celu napisania nawet prostego programu należało program skompilować przed uruchomieniem.
  • Od Javy 9 można uruchamiać proste programy bezpośrednio poleceniem java.
  • Java ma teraz także swój “terminal” w postaci jshell, który pozwala pisać pojedyncze instrukcje (linia po linii lub z pliku), bez wymogu tworzenia klas i metod.
  • Na upartego można proste programy Javy uruchamiać po zamianie ich na skrypty z shebang.

Piotr Przybył

Notoryczny inżynier w pracy i poza nią, podążający za meandrami sztuki programowania. Zawodowo Remote Freelance Software Gardener, od kilku lat wyrywający chwasty w ogródkach webowych i zwykle przycinający Javę do kształtów pożądanych przez klientów. Miłośnik lekkości i zwinności, która powinna przejawiać się przede wszystkim w stosowaniu właściwych narzędzi. Lead developer, trener, prelegent.
Komentarze
Ostatnie posty
Data Science News #204
Data Science News #203
Data Science News #202
Data Science News #201