Java pierwszy program to klasa z metodą main, którą kompilujecie poleceniem javac, a uruchamiacie poleceniem java. Od Javy 25 ten sam program może mieć jedną linijkę w metodzie void main() i obywać się bez deklaracji klasy, bo funkcja z JEP 512 przestała być podglądem i jest częścią języka. W tej lekcji poznacie oba zapisy i dowiecie się, kiedy który ma sens.
To czwarta lekcja kursu Javy dla testerów. Pod filmem jest pełna wersja tekstowa: budowa klasy z main, kompilacja i uruchomienie z terminala, nowa składnia Javy 25, sześć typowych błędów z prawdziwymi komunikatami kompilatora, pierwszy program, który otwiera przeglądarkę, oraz ćwiczenie z rozwiązaniem. Każdy przykład uruchomiliśmy 10 października 2026 roku na JDK Temurin 25.0.2, a przykłady dla starszej wersji na Temurin 21.0.12.1.
Spis treści
- Jak wygląda pierwszy program w Javie?
- Jak skompilować i uruchomić program z terminala?
- Co zmienia Java 25: compact source files i instancyjna metoda main
- Który zapis wybrać w kursie i w testach?
- Jakie błędy popełniają początkujący?
- Java pierwszy program w pracy testera: Playwright w metodzie main
- Ćwiczenie z rozwiązaniem
Jak wygląda pierwszy program w Javie?
Klasyczny pierwszy program w Javie ma pięć linii i każda coś znaczy. Zapiszcie go w pliku HelloWorld.java. Nazwa pliku musi być dokładnie taka jak nazwa publicznej klasy, z wielkimi literami włącznie.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Witaj, testerze!");
}
}
Według specyfikacji języka Java SE 25 (rozdział 12.1, 2025) maszyna wirtualna zaczyna wykonanie od metody main wskazanej klasy. Do Javy 24, poza trybem podglądu, taka metoda musiała być publiczna, statyczna i przyjmować tablicę napisów, stąd ta słynna linijka, którą pokolenia programistów przepisywały, zanim zrozumiały z niej choć połowę.
Jak skompilować i uruchomić program z terminala?
Program w Javie przechodzi dwa etapy. Kompilator javac zamienia kod źródłowy na kod bajtowy w pliku .class, a polecenie java uruchamia ten kod bajtowy w maszynie wirtualnej. Dlatego ten sam plik .class działa na Windows, macOS i Linuxie.
Droga od kodu do wyniku
1. Kod źródłowy
HelloWorld.java, tekst, który piszecie w edytorze
2. javac
kompilator sprawdza składnię i typy, przy błędzie zatrzymuje się z komunikatem
3. Kod bajtowy
HelloWorld.class, niezależny od systemu operacyjnego
4. java
maszyna wirtualna ładuje klasę i wywołuje main
Cały scenariusz lekcji Java pierwszy program zamyka się w dwóch poleceniach. W terminalu, w katalogu z plikiem:
javac HelloWorld.java
java HelloWorld
Witaj, testerze!
Zwróćcie uwagę, że przy java podajecie nazwę klasy, bez rozszerzenia. Kompilujecie plik, uruchamiacie klasę. Po kompilacji w katalogu pojawi się plik HelloWorld.class. Istnieje też skrót: według JEP 330 od Javy 11 polecenie java HelloWorld.java kompiluje plik w pamięci i od razu go uruchamia, bez zostawiania pliku .class. Według JEP 458 od Javy 22 ten sam tryb obsługuje program złożony z kilku plików źródłowych. Do nauki i krótkich skryptów to wygoda, ale w projekcie Maven z poprzedniej lekcji kompilacją i tak zajmuje się Maven.
Co zmienia Java 25: compact source files i instancyjna metoda main
Java 25 pozwala napisać ten sam program bez deklaracji klasy, bez public, bez static i bez parametru args. Według strony JEP 512 w OpenJDK funkcja ma status Closed / Delivered w wydaniu 25, czyli jest stałą częścią języka, a nie podglądem włączanym flagą. Wcześniej przeszła cztery rundy podglądu: w Javie 21 (JEP 445), 22 (JEP 463), 23 (JEP 477) i 24 (JEP 495). Zapiszcie plik Witaj.java:
void main() {
IO.println("Witaj, testerze! To compact source file z Javy 25.");
}
java Witaj.java
Witaj, testerze! To compact source file z Javy 25.
Ten zapis to tak zwany compact source file, czyli zwarty plik źródłowy. Klasa nadal istnieje, tylko kompilator deklaruje ją za Was. Według JEP 512 nowa klasa IO leży w pakiecie java.lang, więc nie wymaga importu, ale jej metody wywołujecie z nazwą klasy, czyli IO.println, a nie samym println. Zwarty plik źródłowy automatycznie importuje też klasy z modułu java.base, dlatego poniżej List działa bez żadnej linii import:
void main(String[] args) {
String srodowisko = args.length > 0 ? args[0] : "test";
int liczbaTestow = 3;
IO.println("Środowisko: " + srodowisko);
IO.println("Do uruchomienia: " + liczbaTestow + " testy logowania");
List<String> przegladarki = List.of("chromium", "firefox", "webkit");
IO.println("Przeglądarki: " + przegladarki);
}
java Logowanie.java
Środowisko: test
Do uruchomienia: 3 testy logowania
Przeglądarki: [chromium, firefox, webkit]
Uruchomienie zwartego pliku na starszej Javie kończy się błędem kompilacji. Tak zareagował javac z JDK 21 na plik Witaj.java:
Witaj.java:1: error: unnamed classes are a preview feature and are disabled by default.
void main() {
^
(use --enable-preview to enable unnamed classes)
1 error
Na stronie wprowadzenia do kursu ten sam plik daje inny komunikat: implicitly declared classes are not supported in -source 21. To nie sprzeczność, tylko inny kompilator. Powyżej odpowiada javac z JDK 21, który zna tę funkcję jako podgląd pod starą nazwą „unnamed classes”. Komunikat z wprowadzenia daje javac z JDK 25 uruchomiony z opcją --release 21: kompilator zna już funkcję pod nową nazwą, ale odmawia jej użycia, bo każecie mu celować w Javę 21. Oba komunikaty sprawdziliśmy 11.10.2026.
Jedna funkcja, trzy nazwy
W komunikacie z JDK 21 widać nazwę „unnamed classes”. To nie pomyłka: według historii opisanej w JEP 512 funkcja zaczynała jako klasy nienazwane, potem nazywała się „implicitly declared classes”, a w Javie 25 przyjęła nazwę compact source files. Jeśli więc w starszym kursie albo na Stack Overflow traficie na którąkolwiek z tych nazw, chodzi o to samo. A flaga --enable-preview z komunikatu na Javie 21 nie jest dobrym pomysłem w projekcie testów: podgląd zmieniał się między wersjami, więc kod z Javy 21 nie musi skompilować się na Javie 25.
IntelliJ IDEA od wersji wspierającej Javę 25 ma osobny szablon pliku. Według dokumentacji JetBrains tworzycie go przez New | Java Compact File, a gdy program urośnie, akcja Convert into a regular class (Alt+Enter na void main()) zamieni go w zwykłą klasę, którą przeniesiecie do pakietu.
Który zapis wybrać w kursie i w testach?
Wasz Java pierwszy program może mieć dowolną z dwóch form. W kursie zobaczycie oba zapisy, a w projektach testów prawie zawsze klasyczny. Test JUnit to metoda w klasie w pakiecie, uruchamiana przez framework, a nie przez main, więc zwarty plik źródłowy nie ma w nim zastosowania. Zwarty plik świetnie sprawdza się za to w trzech sytuacjach, które tester zna z codziennej pracy:
- szybkie sprawdzenie, jak działa metoda z biblioteki standardowej, zanim użyjecie jej w teście;
- mały skrypt, który generuje dane testowe albo czyta plik z wynikami;
- nauka składni, gdy nie chcecie jeszcze myśleć o pakietach i modyfikatorach dostępu.
Jeśli Wasz projekt w pracy jest na Javie 21, a w wielu firmach tak jest, piszcie klasycznie. Według harmonogramu wsparcia Oracle z 2026 roku Java 21 ma wsparcie Premier do września 2028, więc ten kod jeszcze długo będzie żył obok nowego.
Jakie błędy popełniają początkujący?
Java pierwszy program rzadko kompiluje się za pierwszym razem i to dobra wiadomość, bo komunikaty kompilatora uczą najszybciej. Wszystkie komunikaty poniżej wywołaliśmy celowo na JDK 25. Kompilator Javy mówi po angielsku i bywa lakoniczny, ale zawsze podaje plik, numer linii i znaczek ^ pod miejscem, w którym się zgubił.
Dwa z tych błędów w pełnej postaci, bo ich wygląd warto zapamiętać. Brak średnika:
Srednik.java:3: error: ';' expected
System.out.println("Brakuje średnika")
^
1 error
I polskie cudzysłowy, które wpadają do kodu przy kopiowaniu z dokumentu tekstowego albo z czatu. Edytor tekstu chciał dobrze, typograficznie ładnie, a kompilator odpowiada dwoma błędami, po jednym na każdy elegancki znak.
Cudzyslow.java:3: error: illegal character: '\u201e'
System.out.println(„Polski cudzysłów”);
^
Cudzyslow.java:3: error: illegal character: '\u201d'
System.out.println(„Polski cudzysłów”);
^
Zasada przy czytaniu komunikatów: zaczynajcie od pierwszego błędu na liście. Jeden brakujący średnik albo nawias potrafi wywołać kilka kolejnych komunikatów, które znikną same po poprawce pierwszego.
Java pierwszy program w pracy testera: Playwright w metodzie main
Metoda main to najkrótsza droga do sprawdzenia, czy narzędzie w ogóle działa na Waszym komputerze, zanim zbudujecie wokół niego testy. Dokumentacja Playwright for Java zaczyna dokładnie od takiego programu. Poniższy kod uruchamia przeglądarkę Chromium bez okna, otwiera stronę i wypisuje jej tytuł. Wymaga projektu Maven z lekcji o IntelliJ i zależności com.microsoft.playwright:playwright, według Maven Central w wersji 1.63.0 z września 2026 roku. Według dokumentacji Playwright wymaga Javy 8 lub nowszej, więc JDK 25 z poprzednich lekcji wystarczy z zapasem.
package pl.qualityisland;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
public class PierwszyPlaywright {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch();
Page page = browser.newPage();
page.navigate("https://qualityisland.pl/");
System.out.println("Tytuł strony: " + page.title());
}
}
}
Uruchomiliśmy ten program w projekcie Maven na JDK 25. Wynik:
Tytuł strony: Quality Island firma QA, testy oprogramowania, szkolenia IT
Widzicie w nim wszystko z tej lekcji: pakiet, klasę, metodę main i System.out.println. Następnym krokiem jest zamiana wypisywania tytułu na asercję w teście JUnit, co pokazujemy na szkoleniu automatyzacja testów z Playwright w Javie. Jeśli w Waszym zespole standardem jest Selenium, ta sama ścieżka prowadzi przez szkolenie automatyzacja testów Selenium WebDriver. W naszej praktyce zachęcamy, żeby pierwszy program uruchomić w terminalu, a nie tylko zieloną strzałką w IDE, bo dokładnie tak, poleceniem w konsoli, uruchamia kod pipeline CI. W Quality Island przeszkoliliśmy ponad 2 500 specjalistów i tę radę warto przyjąć od pierwszego dnia nauki.
Ćwiczenie z rozwiązaniem
Zadanie: napiszcie program DaneTestowe, który przyjmuje z wiersza poleceń imię i nazwę środowiska, a wypisuje login testowy w formacie imie.srodowisko@example.com małymi literami. Gdy argumentów brak, ma użyć wartości Anna i test. Napiszcie dwie wersje: zwarty plik źródłowy dla Javy 25 i klasyczną klasę dla Javy 21.
To zadanie łączy wszystko z lekcji Java pierwszy program: metodę main, argumenty i wypisywanie tekstu. Rozwiązanie dla Javy 25:
void main(String[] args) {
String imie = args.length > 0 ? args[0] : "Anna";
String srodowisko = args.length > 1 ? args[1] : "test";
String email = imie.toLowerCase() + "." + srodowisko + "@example.com";
IO.println("Użytkownik testowy: " + imie);
IO.println("Login: " + email);
}
Rozwiązanie dla Javy 21 i starszych projektów:
public class DaneTestowe {
public static void main(String[] args) {
String imie = args.length > 0 ? args[0] : "Anna";
String srodowisko = args.length > 1 ? args[1] : "test";
String email = imie.toLowerCase() + "." + srodowisko + "@example.com";
System.out.println("Użytkownik testowy: " + imie);
System.out.println("Login: " + email);
}
}
java DaneTestowe.java
java DaneTestowe.java Marek staging
Użytkownik testowy: Anna
Login: anna.test@example.com
Użytkownik testowy: Marek
Login: marek.staging@example.com
Zapis warunek ? a : b to operator warunkowy: gdy argument istnieje, bierze go, w przeciwnym razie wartość domyślną. Więcej o warunkach znajdziecie w lekcji o instrukcji warunkowej if. Klasyczną wersję uruchomiliśmy na JDK 21 i dała identyczny wynik. Typ String i metodę toLowerCase() omawiamy dokładniej w lekcji o łańcuchach znakowych, a skąd w ogóle typy danych, wyjaśnia lekcja o typach danych w Javie.
O tym, jak programowanie zmienia codzienną pracę testerów i zespołów QA, piszemy także na portalu Strefa QA, skierowanym do zespołów jakości i ich liderów.
Co zabrać z tego artykułu
01Java pierwszy program w klasycznej postaci to klasa z public static void main(String[] args), a nazwa pliku musi zgadzać się z nazwą publicznej klasy.
02Kompilujecie plik (javac HelloWorld.java), uruchamiacie klasę (java HelloWorld); od Javy 11 działa też java HelloWorld.java.
03W Javie 25 compact source files i void main() są finalne (JEP 512); na Javie 21 ten zapis się nie skompiluje.
04W projektach testów piszecie klasy w pakietach, zwarte pliki zostawcie na naukę i skrypty.
05Czytajcie pierwszy komunikat kompilatora: plik, numer linii i znaczek ^ wskazują miejsce błędu.
Źródło: OpenJDK (JEP 330, 458, 512), specyfikacja Java SE 25, Playwright for Java; kod uruchomiony 10.10.2026 na Temurin 25.0.2 i 21.0.12.1.
Na szkoleniu Java dla testerów przechodzicie od pierwszego programu do testów automatycznych z trenerem i na własnym projekcie, bez kopiowania gotowców.
Powiązane na blogu Quality Island
- Instalacja środowiska Java: JDK 25, JAVA_HOME i PATH
- IntelliJ IDEA pierwszy projekt: Maven, JDK 25 i JUnit
- Komentarze w kodzie
- Java dla testerów automatyzujących: plan nauki
- Książki do nauki Javy: 10 tytułów dla testera
Pełna lista źródeł
- OpenJDK, JEP 512: Compact Source Files and Instance Main Methods, 2025. Status Closed / Delivered w JDK 25, historia podglądów JEP 445, 463, 477 i 495, klasa IO w java.lang, automatyczny import java.base.
- OpenJDK, JEP 330: Launch Single-File Source-Code Programs, 2018. Uruchamianie pliku .java bez osobnej kompilacji od Javy 11.
- OpenJDK, JEP 458: Launch Multi-File Source-Code Programs, 2024. Tryb uruchamiania z kodu źródłowego dla wielu plików od Javy 22.
- Oracle, The Java Language Specification, Java SE 25 Edition, rozdział 12 Execution, 2025. Uruchomienie programu od metody main.
- Oracle, The javac Command, JDK 25, 2025. Opcje kompilatora, w tym –release.
- Oracle, Oracle Java SE Support Roadmap, 2026. Wsparcie Premier Javy 21 do września 2028.
- JetBrains, Create your first Java application, 2026. Szablon Java Compact File i akcja Convert into a regular class.
- Microsoft, Playwright for Java: Installation, 2026. Pierwszy skrypt z metodą main, wymagania systemowe, Java 8 lub nowsza.
- Maven Central, com.microsoft.playwright:playwright, 2026. Wersja 1.63.0, odczyt 10.10.2026.