
Przyznaję się bez bicia: mam ulubione pytanie na rozmowie kwalifikacyjnej z Javy. Jest skomplikowane mniej więcej jak spinacz biurowy. „Czym się różni == od equals()?”
Brzmi banalnie, prawda? Zna je każdy, kto uczy się Javy od kilku tygodni. Kandydat odpowiada z uśmiechem: „== porównuje referencje, equals() porównuje zawartość”. Świetnie. I wtedy pokazuję taki kod:
Integer small1 = 127;
Integer small2 = 127;
Integer big1 = 128;
Integer big2 = 128;
boolean sameSmall = small1 == small2; // true
boolean sameBig = big1 == big2; // falseI w pokoju robi się bardzo, bardzo cicho.
Nie chodzi o to, że kandydat jest słaby. Chodzi o to, że wykuł odpowiedź na pamięć, zamiast zrozumieć, jak to działa. Java cache'uje obiekty Integer w zakresie od −128 do 127, więc 127 to jeden i ten sam obiekt, a 128 daje dwa różne. Ktoś, kto rozumie, wyjaśni to w dziesięć sekund. Ktoś, kto wykuł, będzie się bardzo, bardzo długo wpatrywać w ekran.
Tak właśnie wygląda rozmowa kwalifikacyjna na Java developera w 2026 roku. Pytania są prawie takie same jak pięć lat temu. Zmieniło się co innego: teraz prawie zawsze pada dopytanie „a dlaczego?” — i druga odpowiedź od razu pokazuje, czy to wiedza wykuta na pamięć, czy prawdziwe zrozumienie.
Iść na taką rozmowę po wkuciu listy „top 100 pytań rekrutacyjnych z Javy” to jak wejść na ring z Mike'iem Tysonem, bo obejrzało się parę jego walk na YouTube. Formalnie jesteś na ringu. Ale pierwsze dopytanie wyląduje szybciej, niż zdążysz powiedzieć „tego nie było w tutorialu”.
Rozbierzmy na części, o co rekruterzy pytają teraz, gdzie ludzie najczęściej się potykają i jak się przygotować, żeby dopytania cieszyły, a nie straszyły.
Co się zmieniło w pytaniach rekrutacyjnych Java w 2026 roku
Krótko: podstawowe pytania z Core Javy prawie się nie zmieniają, ale w 2026 roku dochodzi do nich nowoczesna Java (17, 21 i 25), Spring Boot 4 i nowy format — live coding, na którym czasem wolno korzystać z AI.
Trzy największe zmiany:
- Java 25 to aktualny LTS. Wyszła we wrześniu 2025 roku i jest pierwszym wydaniem z długoterminowym wsparciem od czasu Javy 21. Rekruterzy coraz częściej pytają nie tylko „co nowego w Javie 8”, ale też o recordy, sealed classes, pattern matching i virtual threads.
- Spring Boot 4. Wydany w listopadzie 2025 roku razem ze Spring Framework 7: przejście na Jackson 3, adnotacje JSpecify dla null safety, wbudowane wersjonowanie API. Jeśli w ogłoszeniu jest Spring, spodziewaj się pytania czy dwóch o nową główną wersję.
- AI na rozmowie. Niektóre firmy już pozwalają kandydatom korzystać z AI na rozmowach technicznych, a Canva od 2025 roku wręcz tego wymaga od kandydatów na backend, frontend i machine learning. Ale mnóstwo firm nadal tego zabrania. Zasada jest prosta: zapytaj rekrutera z wyprzedzeniem.
Jak wygląda rozmowa kwalifikacyjna na Java developera
Zwykle to nie jedna rozmowa, tylko kilka etapów:
- Screening z rekruterem — motywacja, doświadczenie, oczekiwania finansowe. Bez kodu, ale sprawdzają, czy da się z tobą normalnie dogadać.
- Screening techniczny — 30–45 minut szybkich pytań z podstaw, żeby inżynierowie nie tracili czasu na osoby, które jeszcze nie są na tym poziomie.
- Rozmowa techniczna — 60–90 minut: Core Java, kolekcje, wielowątkowość, Spring, bazy danych i cała masa „dlaczego”.
- Live coding albo zadanie domowe — rozwiązujesz zadanie na oczach rekrutera albo w domu.
- Runda finałowa — zespół, procesy, jak radzisz sobie z konfliktami i deadline'ami. O HashMap nikt tu już nie pyta. Pytają, co zrobisz, jeśli produkcja padnie w piątek o 18:00.

Juniorzy dostają głównie pytania z podstaw. Im wyższe stanowisko, tym mniej teorii i więcej rozmowy o realnym doświadczeniu: co udało się zbudować, jakie decyzje zapadły i gdzie coś poszło nie tak.
Dalej: pytania rekrutacyjne Java według tematów. To nie jest wyczerpująca lista — tylko najczęstsze pytania z krótkimi odpowiedziami i pułapkami, w które ludzie wpadają. Szczegółowe omówienie setek pytań znajdziesz w naszej serii na CodeGym Badanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java — jeszcze do niej wrócimy.
Pytania rekrutacyjne Core Java: podstawy, których nie przeskoczysz
Czym się różnią typy prymitywne od referencyjnych? Zmienna prymitywna przechowuje samą liczbę albo znak, a zmienna referencyjna — adres obiektu, który żyje na stercie (heap). I tak wracamy prosto do podchwytliwego pytania z Integerem, od którego zaczęliśmy.
Dlaczego String jest niemutowalny? Jest niemutowalny jak opinia team leada w sprawie tabów i spacji. A na serio — ze względu na bezpieczeństwo, cache'owanie hash code'u i pulę stringów: wiele części programu może bezpiecznie współdzielić ten sam string w tym samym czasie. Jeśli musisz w pętli raz za razem sklejać stringi, użyj StringBuilder, bo inaczej przy każdej iteracji powstaje zupełnie nowy obiekt.
Jak są powiązane equals() i hashCode()? Jedna zasada: obiekty równe według equals() muszą zwracać ten sam hashCode(). Ale to, że różne obiekty mają ten sam hashCode(), jest całkowicie w porządku — to zwykła kolizja. Nadpisz equals(), zapomnij o hashCode() i masz gwarantowany przepis na obiekty, których HashMap „nie może znaleźć”, choć leżą tuż pod nosem.
Czy Java przekazuje obiekty przez referencję, czy przez wartość? Ulubieniec publiczności, na którym wykładają się nawet pewni swego developerzy na poziomie mid. Jeśli chcesz zabłysnąć, powiedz tak: „Java zawsze przekazuje przez wartość — czasem ta wartość po prostu jest referencją”. Brzmi jak wróżba z chińskiego ciasteczka, a działa za każdym razem. Dlatego metoda może zmienić pola przekazanego jej obiektu, ale nie może podmienić obiektu, na który wskazuje twoja zewnętrzna zmienna.
Co zwróci ta metoda?
static String pick() {
try {
return "try";
} finally {
return "finally";
}
}
Odpowiedź: "finally". Blok finally wykonuje się zawsze, a jego return nadpisuje return z try. finally jest jak ostatni komentarz w code review: zawsze ma ostatnie słowo. Rekruterzy nie pokazują tego kodu dlatego, że ktokolwiek powinien tak pisać — chcą sprawdzić, czy rozumiesz kolejność wykonywania. A poprawna odpowiedź na pytanie „czy tak w ogóle można pisać?” brzmi: nie. Nigdy.
Wyjątki: co się sypie i kto za to odpowiada
Pytania o wyjątki wydają się nudne dokładnie do momentu, w którym produkcja pada przez połknięty catch.
- Checked vs. unchecked: jaka jest różnica? Przy wyjątkach checked kompilator zmusza cię, żeby je obsłużyć albo zadeklarować w throws — na przykład IOException przy pracy z plikiem. Unchecked, czyli podklasy RuntimeException, to zwykle błędy w samym kodzie, jak NullPointerException czy IllegalArgumentException, i kompilator nie każe ich obsługiwać. Mocna odpowiedź na rozmowie dodaje: checked są na sytuacje, z których program może się sensownie podnieść, unchecked — na bugi, które trzeba naprawić, a nie łapać.
- Co robi try-with-resources? Wszystko, co zadeklarujesz w nawiasach po try i co implementuje AutoCloseable, zostaje automatycznie zamknięte, nawet jeśli w środku poleci wyjątek:
try (var reader = Files.newBufferedReader(Path.of("orders.csv"))) {
return reader.readLine();
}Koniec z blokami finally z ręcznym close() i zagnieżdżonym try w środku finally — tak to wyglądało przed Javą 7.
- Czy można złapać OutOfMemoryError? Technicznie tak: to podklasa Throwable. Ale OutOfMemoryError to Error, a nie Exception — sygnał problemu, z którym program zwykle nie poradzi sobie elegancko. Łapanie go, żeby „jechać dalej”, to jak przestawianie leżaków na Titanicu. Jedyny rozsądny ruch to zalogować błąd i czysto zamknąć aplikację.
OOP: przykłady, nie definicje
Błąd numer jeden to odpowiadanie podręcznikowymi definicjami. „Enkapsulacja to ukrywanie danych”. Dzięki — ale gdzie ci się to kiedykolwiek przydało w kodzie?
- Klasa abstrakcyjna czy interfejs? Interfejs opisuje, co obiekt potrafi, a klasa może implementować wiele interfejsów. Klasa abstrakcyjna to wspólny fundament ze stanem i częściową implementacją — i rozszerzyć można tylko jedną. Od Javy 8 interfejsy mają metody default, więc granica się rozmyła, a rekruterzy uwielbiają o to pytać.
- Overloading vs. overriding. Overloading (przeciążanie) to metody o tej samej nazwie i różnych parametrach, rozstrzygane w czasie kompilacji. Overriding (nadpisywanie) to sytuacja, w której podklasa dostarcza nową implementację metody rodzica, rozstrzyganą w czasie działania programu.
- Jak zrobić klasę niemutowalną? Pola private final, żadnych setterów, klasa final albo z prywatnym konstruktorem, a wszystkie mutowalne obiekty w środku kopiujemy na wejściu i na wyjściu. Albo po prostu użyj recordu — więcej o tym niżej.
Kolekcje w Javie: pytanie o HashMap murowane
Jeśli dostaniesz tylko jedno pytanie o kolekcje, będzie o HashMap. Jeśli dwa, drugie też będzie o HashMap.
Jak działa HashMap pod maską? W środku jest tablica „kubełków” (buckets). hashCode() klucza wybiera kubełek, a w kubełku wpisy są przechowywane jako lista. Jeśli w jednym kubełku znajdzie się więcej niż osiem wpisów (a tablica ma już co najmniej 64 kubełki), lista zamienia się w drzewo czerwono-czarne, żeby wyszukiwanie nie zwalniało. Gdy tablica zapełni się w 75% — to domyślny load factor — podwaja rozmiar, a wszystkie wpisy są rozkładane na nowo.

A teraz pułapka:
Map<List<Integer>, String> map = new HashMap<>();
List<Integer> key = new ArrayList<>(List.of(1));
map.put(key, "value");
key.add(2);
String found = map.get(key); // nullZmieniliśmy klucz już po włożeniu go do mapy. Zmienił się jego hashCode(), więc HashMap szuka go w innym kubełku i nic nie znajduje. Wpis nadal jest w mapie — po prostu nie da się go już wyciągnąć tym kluczem. Stąd złota zasada: klucze w HashMap powinny być niemutowalne.
Inne częste pytania:
- ArrayList czy LinkedList? W prawdziwym kodzie prawie zawsze ArrayList: dostęp po indeksie jest natychmiastowy, a dane leżą w pamięci zwarcie, jedne przy drugich. LinkedList wygrywa tylko w rzadkich scenariuszach z częstym wstawianiem w środek przez iterator. Wszyscy znają ją z podręczników, ale prawie nikt nie widział jej na produkcji — trochę jak Yeti.
- ConcurrentHashMap czy Collections.synchronizedMap()? Obie są thread-safe, ale synchronizedMap blokuje całą mapę, a ConcurrentHashMap pozwala wielu wątkom pracować z nią równolegle.
- Skąd się bierze ConcurrentModificationException? Z modyfikowania kolekcji podczas przechodzenia po niej pętlą for-each. Żeby usuwać elementy w trakcie iteracji, użyj iteratora albo removeIf().
Stream API: jedna linijka kodu, trzy linijki pytań
Rekruterzy kochają streamy, prawdziwy kod zresztą też. Tyle że w streamach bardzo łatwo napisać coś pięknego i błędnego jednocześnie.
- Dlaczego mój stream „nic nie robi”? Operacje takie jak filter, map i sorted są pośrednie: zwracają nowy stream i same niczego nie uruchamiają. Streamy są leniwe: praca zaczyna się dopiero przy operacji terminalnej — collect, count, forEach. Do tego momentu żaden element nie zostanie nawet dotknięty. Stąd pułapka: napiszesz stream z map, zapomnisz o operacji terminalnej — i kod w map nigdy się nie wykona. Stream bez operacji terminalnej jest jak lista zadań na poniedziałek: pięknie rozpisana, a nic się nie dzieje.
- map() czy flatMap()? map to jeden element na wejściu i jeden na wyjściu. flatMap zamienia każdy element w cały stream, a potem scala je wszystkie w jeden strumień. Klasyczny przykład to „spłaszczenie” listy list:
List<List<String>> teams = List.of(
List.of("Anna", "Ben"),
List.of("Vicky"));
List<String> people = teams.stream()
.flatMap(List::stream)
.toList(); // [Anna, Ben, Vicky]- Czy można użyć streamu dwa razy? Nie. Po operacji terminalnej stream jest zamknięty, a ponowne wywołanie rzuca IllegalStateException. Potrzebujesz go jeszcze raz? Utwórz nowy.
- Optional: jak ludzie go psują? Optional mówi ci uczciwie: wartości może nie być. Najprostszy sposób, żeby to zepsuć, to wywołać get() na ślepo — to ten sam stary NullPointerException, tylko w okularach i z doklejonymi wąsami. Drugi sposób to zrobienie z Optional pola klasy albo parametru metody: został zaprojektowany jako typ zwracany. Właściwe narzędzia to orElse, orElseThrow, map i ifPresent.
- Co to jest interfejs funkcyjny? Interfejs z dokładnie jedną metodą abstrakcyjną, jak Runnable, Comparator czy Function. Właśnie takie interfejsy można zaimplementować lambdą. Adnotacja @FunctionalInterface nie jest obowiązkowa, ale prosi kompilator, żeby sprawdził, czy metoda abstrakcyjna naprawdę jest tylko jedna.
Pytania rekrutacyjne z wielowątkowości w Javie: tu odpada najwięcej midów
To tutaj odsiewa się większość kandydatów na poziom mid. Bo wielowątkowości nie da się wykuć ze ściągi — trzeba ją zrozumieć. I trochę się jej bać: to zdrowy odruch.
- Co gwarantuje volatile? Widoczność zmian między wątkami: zapis do zmiennej volatile przez jeden wątek jest od razu widoczny dla innych. Ale volatile nie daje atomowości: count++ to odczyt, dodawanie i zapis, więc dwa wątki nadal mogą zgubić czyjąś aktualizację.
- Co to jest happens-before? Reguła, która gwarantuje, że wyniki jednej akcji są widoczne dla innej. Na przykład wszystko, co wątek zrobił przed zwolnieniem monitora, zobaczy wątek, który jako następny ten monitor przejmie.
- Jak powstaje deadlock? Dwa wątki biorą te same locki w różnej kolejności i czekają na siebie w nieskończoność. Jak dwie wyjątkowo uprzejme osoby w wąskim korytarzu: „Ależ proszę przodem” — i tak aż do fajrantu. Rozwiązanie to stała kolejność zakładania locków, a namierzyć problem pomoże thread dump.
- Runnable czy Callable? Callable może zwrócić wynik i rzucić checked exception. Zwykle uruchamia się je przez ExecutorService, a nie ręcznie przez new Thread().
Wielowątkowość to osobny, duży temat — więcej znajdziesz w sekcji o wielowątkowości w naszym artykule Top 50 pytań i odpowiedzi na rozmowie o pracę dla Java Core, część 2.
Nowoczesna Java: o co pytają na rozmowach w 2026 roku
Tej części pięć lat temu na rozmowach w ogóle nie było — i właśnie dlatego wyróżnia osoby, które nadążają za językiem.
Co to jest record? Kompaktowa klasa na niemutowalne dane:
record Point(int x, int y) {}Jedna linijka i masz już konstruktor, gettery x() i y(), equals(), hashCode() i toString(). Wszystkie pola są final. Gdzieś w kącie Lombok po cichu pakuje walizki. Idealne na DTO i na te klucze do HashMap — chyba że twój record trzyma mutowalną ArrayList: final chroni referencję, a nie zawartość listy.
Po co są sealed classes? Jawnie wymieniają, kto może po nich dziedziczyć. W połączeniu z pattern matchingiem w switch kompilator zna wszystkie możliwe warianty i ostrzeże cię, jeśli któryś nie jest obsłużony.
Co to są virtual threads? Lekkie wątki zarządzane przez JVM, a nie przez system operacyjny. Dziesięć tysięcy to żaden problem, a można dojść do setek tysięcy:
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> callSlowService());
}
}Dobre pytanie na rozmowie brzmi tak: kiedy virtual threads nie pomogą? Odpowiedź: kiedy zadanie jest CPU-bound, a nie polega na czekaniu. Virtual threads błyszczą tam, gdzie kod dużo czeka — sieć, baza danych, zewnętrzne serwisy. Ale nie przyspieszą zadania obliczeniowego, tak jak nowy fotel biurowy nie sprawi, że zaczniesz szybciej kodować.

Bonus na poziomie mid: virtual thread kiedyś „przyklejał się” (pinning) do swojego wątku platformowego, jeśli blokował się wewnątrz synchronized, i cała korzyść szła do kosza. Java 24 to naprawiła, ale o tej pułapce warto wiedzieć — projekty na Javie 21 nigdzie się nie wybierają.
Co nowego w Javie 25? Nie musisz wymieniać wszystkich zmian, ale parę warto znać. Na przykład można teraz napisać program bez deklarowania klasy i z uproszczoną metodą main — to ukłon w stronę osób, które dopiero zaczynają naukę języka. A konstruktory mogą teraz wykonać kod przed wywołaniem super(), na przykład żeby zwalidować argumenty.
JVM i pamięć
- Z jakich obszarów składa się pamięć JVM? Ze sterty (heap), na której żyją obiekty; ze stosu każdego wątku, z lokalnymi zmiennymi i wywołaniami metod; oraz z metaspace, gdzie przechowywane są metadane klas.
- Jak działa garbage collector? Usuwa obiekty, do których nie prowadzi już żadna referencja z „żywych” części programu. Pomyśl o nim jak o ekipie sprzątającej w biurze: wyrzuca tylko to, po co nikt się nie zgłasza. Kubek z karteczką „NIE RUSZAĆ” zostaje na miejscu, nawet jeśli stoi tam od trzech lat. Większość obiektów żyje bardzo krótko, więc sterta jest podzielona na generacje: młode obiekty są sprzątane często i szybko, stare rzadziej.
- Czy w Javie mogą być wycieki pamięci? Tak. Garbage collector nie usunie obiektu, do którego coś nadal trzyma referencję. Klasyczny przykład to statyczna kolekcja, do której tylko się dodaje i której nikt nigdy nie czyści. Ten sam kubek z karteczką, tylko że ważący gigabajt. Albo ta HashMap ze zmienionym kluczem: wpisy zostają, ale nie da się ich wyciągnąć.
Pytania rekrutacyjne ze Spring Boot i baz danych
Jeśli w ogłoszeniu jest Spring — a prawie zawsze jest (czasem mam wrażenie, że nawet w ogłoszeniach na baristę) — przygotuj się do tego bloku osobno.
- IoC i DI: co to jest i dlaczego wstrzykiwanie przez konstruktor jest lepsze? Spring sam tworzy obiekty i przekazuje im zależności. Wstrzykiwanie przez konstruktor jest lepsze, bo zależności widać od razu, pola mogą być final, a klasę łatwo przetestować bez Springa.
- Dlaczego @Transactional nie działa? Klasyka: metoda z adnotacją @Transactional jest wywoływana z innej metody tej samej klasy. Transakcjami zarządza proxy, a wywołanie z wnętrza klasy omija je bokiem — jak pracownik, który wślizguje się tylnymi drzwiami i nigdy nie odbija karty. To jedno z najczęstszych pytań na poziomie mid.
- Co to jest problem N+1? Ładujesz listę 100 zamówień jednym zapytaniem, a potem dla każdego zamówienia pobierasz klienta osobnym zapytaniem. To 101 zapytań zamiast jednego czy dwóch. A baza danych w tym czasie cichutko płacze. Rozwiązanie to JOIN FETCH albo EntityGraph.
- Jakie są poziomy izolacji transakcji? Od READ UNCOMMITTED do SERIALIZABLE. Samo wymienienie nie wystarczy — trzeba wyjaśnić, przed jakimi anomaliami chroni każdy z nich: dirty reads, non-repeatable reads, phantom reads.
- INNER JOIN czy LEFT JOIN? Wyobraź sobie dwie tabele: klientów i zamówień. INNER JOIN zostawia tylko klientów, którzy mają co najmniej jedno zamówienie — reszta po prostu znika z wyniku. LEFT JOIN zostawia wszystkich klientów, a ci bez zamówień dostają NULL w kolumnach zamówień. Klasyczne pytanie na zrozumienie: jak znaleźć klientów, którzy nie mają żadnego zamówienia? Odpowiedź: LEFT JOIN plus warunek, że kolumna z tabeli zamówień IS NULL.
- Po co są indeksy i dlaczego nie można zaindeksować wszystkiego? Indeks przyspiesza wyszukiwanie jak spis treści w książce: baza nie musi czytać całej tabeli. Ale każdy indeks spowalnia inserty i update'y, bo też trzeba go aktualizować, i zajmuje miejsce. Dlatego indeksy tworzy się pod realne zapytania, a nie na wszelki wypadek. Indeksowanie wszystkiego to jak zakreślenie zakreślaczem całego podręcznika: jeśli wszystko jest zaznaczone, nic nie jest.

Jeśli bazy danych to twój słaby punkt, na kursie SQL na CodeGym przećwiczysz zapytania w praktyce, aż JOIN-y przestaną straszyć.
Live coding na rozmowie kwalifikacyjnej Java: zadania i AI
Live coding to najstraszniejsza część. Rozwiązywanie zadania, kiedy ktoś patrzy ci na ręce, to stres: nawet zwykła pętla for zaczyna wyglądać podejrzanie. Ale oto sekret: rekruterowi prawie zawsze bardziej zależy na tym, jak myślisz, niż na tym, czy odpowiedź wyszła poprawna.
Co rekruterzy cenią na live codingu:
- Myśl na głos. Milczący kandydat to czarna skrzynka. Kandydat, który rozumuje na głos, pokazuje tok myślenia, nawet jeśli utknie.
- Doprecyzuj wymagania. „Czy na wejściu może być null?”, „Jak duża jest tablica?” — to nie brak ogarnięcia, to profesjonalizm.
- Zacznij od prostego rozwiązania. Najpierw niech działa, potem niech będzie optymalne. Działający brute force wygrywa z genialnym pomysłem, którego nie zdążyło się dokończyć.
Przykład: jak wygląda zadanie na live codingu
Weźmy typowe zadanie z live codingu: znajdź w stringu pierwszy znak, który występuje dokładnie raz. Dla stringa "swiss" odpowiedź to "w".
Krok 1. Doprecyzuj wymagania. Zanim napiszesz jakikolwiek kod, zadaj kilka pytań. Co zwrócić, jeśli takiego znaku nie ma? Czy wielkie i małe litery to różne znaki? Czy string może być pusty? Rekruter odpowie — i zobaczy, że myślisz o przypadkach brzegowych.
Krok 2. Proste rozwiązanie. Dla każdego znaku przejdź cały string i policz, ile razy występuje. Działa, ale to O(n²): na stringu z milionem znaków potrwa to bardzo długo. Powiedz to na głos — rekruter chce zobaczyć, że rozumiesz koszt swojego rozwiązania.
Krok 3. Optymalizacja. Wystarczą dwa przejścia: najpierw policz wszystkie znaki, potem znajdź pierwszy z licznikiem równym jeden. Żeby zachować kolejność znaków, wystarczy LinkedHashMap. A ponieważ takiego znaku może nie być, zwracamy Optional — tak jak ustaliliśmy w sekcji o streamach:
static Optional<Character> firstUnique(String text) {
Map<Character, Integer> counts = new LinkedHashMap<>();
for (char c : text.toCharArray()) {
counts.merge(c, 1, Integer::sum);
}
for (Map.Entry<Character, Integer> entry : counts.entrySet()) {
if (entry.getValue() == 1) {
return Optional.of(entry.getKey());
}
}
return Optional.empty();
}Teraz to O(n): każdy znak jest przetwarzany stałą liczbę razy.
Krok 4. Przetestuj się. Przepuść w głowie kilka przykładów: "swiss" zwraca "w", "aabb" zwraca pusty Optional, pusty string też zwraca pusty Optional. Jeśli rekruter zapyta, czemu LinkedHashMap, a nie HashMap, masz już odpowiedź: zwykła HashMap nie pamięta kolejności wstawiania, więc „pierwszym” znakiem mogłoby się okazać cokolwiek.
A teraz bonus, który mile zaskoczy rekrutera: wystarczy zwykła HashMap, jeśli w drugim przejściu iterujesz po samym stringu, a nie po mapie. Wtedy kolejność wyznacza string, a mapa tylko przechowuje liczniki. Dwie działające opcje i świadomy wybór między nimi — dokładnie to rekruterzy chcą zobaczyć na live codingu.
Na tym polega cały sekret live codingu. Nie genialne rozwiązanie za pierwszym podejściem, tylko jasna ścieżka: doprecyzuj wymagania, rozwiąż prosto, oszacuj złożoność, popraw, przetestuj.

To można używać AI czy nie? Zależy od firmy, a czasem od etapu rozmowy. Jeśli wolno, rekruter zwykle nie patrzy na to, co wygenerowało AI, tylko na to, jak z niego korzystasz: o co prosisz, jak sprawdzasz wynik, czy wyłapujesz błędy. W Canvie na przykład mówią wprost: liczy się nie to, co AI napisało za kandydata, tylko umiejętność przeczytania wygenerowanego kodu, zrozumienia go i poprawienia — oraz wyjaśnienia każdej technicznej decyzji. Jeśli nie umiesz wyjaśnić, co robi kod, AI ci nie pomogło, tylko wpuściło cię w maliny. To jak pójście na egzamin ze ściągą napisaną w języku, którego nie znasz.
Szczerze mówiąc, to najmocniejszy znany mi argument za solidnymi podstawami. AI w sekundę napisze ci HashMap z mutowalnym kluczem. Tylko ty możesz zauważyć, że tak nie powinno być.
Ściąga: co naprawdę sprawdzają pytania rekrutacyjne Java
Każde pytanie na rozmowie ma ukrytą warstwę. Oto co kryje się za najczęstszymi:
| Pytanie | Co naprawdę sprawdzają | Poziom |
| Czym się różni == od equals()? | Czy rozumiesz różnicę między obiektem a referencją do niego | Junior |
| Jak są powiązane equals() i hashCode()? | Czy umiesz napisać klasę, która nie zepsuje HashMap | Junior |
| Jak działa HashMap? | Czy wiesz, co dzieje się pod maską, a nie tylko znasz API | Junior |
| Checked czy unchecked? | Jak będziesz obsługiwać błędy w prawdziwym kodzie | Junior |
| map() czy flatMap()? | Czy naprawdę rozumiesz streamy, czy tylko je kopiujesz | Junior |
| Co gwarantuje volatile? | Czy rozumiesz model pamięci, czy tylko znasz słowo | Mid |
| Dlaczego @Transactional nie działa? | Czy rozumiesz, że Spring działa przez proxy | Mid |
| Co to jest problem N+1? | Czy pilnujesz, co twój ORM robi z bazą danych | Mid |
| Kiedy virtual threads nie pomogą? | Czy nadążasz za językiem i rozumiesz jego ograniczenia | Mid |
| Zadanie na live codingu | Jak myślisz, doprecyzowujesz i sprawdzasz własną pracę | Każdy poziom |
Jak przygotować się do rozmowy kwalifikacyjnej z Javy w trzy tygodnie
Tydzień 1 — podstawy. Core Java, OOP, wyjątki, kolekcje i Stream API. Nie czytaj samych odpowiedzi — pisz kod. Włóż mutowalny klucz do HashMap i zobacz, co się stanie. Zepsuj equals() i hashCode() i znajdź miejsce, w którym wszystko wybucha.
Tydzień 2 — wielowątkowość i nowoczesna Java. Napisz program z deadlockiem i znajdź go thread dumpem. Przepisz kilka klas na recordy. Odpal dziesięć tysięcy virtual threads i zobacz, jak to działa.
Tydzień 3 — Spring, bazy danych i praktyka. Zbuduj małą aplikację w Spring Boot z bazą danych, złap problem N+1 we własnym kodzie i go napraw. I koniecznie zrób kilka próbnych rozmów — z kimś znajomym, z mentorem albo przynajmniej na głos przed lustrem.
I najważniejsza zasada: nie wkuwaj odpowiedzi. Każde pytanie z tego artykułu da się sprawdzić kodem w pięć minut. To, co sprawdzisz własnymi rękami, zostaje na zawsze; to, co wykujesz, wytrzyma do pierwszego „a dlaczego?”.
A potem w pokoju znów zrobi się cicho. Tylko że tym razem dlatego, że rekruter nie będzie miał już nic do dodania.

Gdzie ćwiczyć
Na kursie Javy na CodeGym prawie każdy temat z tego artykułu — od kolekcji i wyjątków po wielowątkowość — przerabiasz na zadaniach z natychmiastową weryfikacją. Błąd w equals() i hashCode() wychodzi od razu, a nie na rozmowie.
A jeśli wolisz dojść do pierwszej oferty pracy z mentorem, code review i projektami do portfolio, mała uwaga: program mentorski Java University prowadzimy po angielsku. Jest w nim też career center, które pomaga z CV i przygotowaniem do rozmów.
Chcesz jeszcze więcej pytań ze szczegółowymi odpowiedziami? Otwórz naszą serię na CodeGym Badanie pytań i odpowiedzi z rozmowy kwalifikacyjnej na stanowisko programisty Java oraz Top 150 najczęściej zadawanych pytań na rozmowach kwalifikacyjnych dla programistów Java. To materiał na wiele wieczorów.
FAQ
Jakie pytania rekrutacyjne z Javy padają w 2026 roku? Fundament się nie zmienia: Core Java, OOP, wyjątki, kolekcje, Stream API, wielowątkowość, JVM, Spring i bazy danych. W 2026 roku dochodzą do tego pytania o nowoczesną Javę — recordy, sealed classes, pattern matching, virtual threads i zmiany w Javie 25 — oraz o Spring Boot 4.
O co pytają na rozmowie kwalifikacyjnej na junior Java developera? Głównie o podstawy: różnica między == a equals(), związek equals() z hashCode(), dlaczego String jest niemutowalny, jak działa HashMap, ArrayList vs. LinkedList, wyjątki checked vs. unchecked, try-with-resources oraz map() vs. flatMap() w Stream API. Sama znajomość odpowiedzi nie wystarczy — trzeba umieć wyjaśnić, dlaczego to działa właśnie tak.
Jakie pytania rekrutacyjne z Javy dostają developerzy na poziomie mid? Wielowątkowość (volatile, happens-before, deadlock, ExecutorService), działanie JVM i garbage collectora, Spring (DI, @Transactional i jego pułapki), Hibernate (problem N+1, lazy loading) oraz poziomy izolacji transakcji. Do tego mnóstwo pytań o realne doświadczenie.
Czy można używać AI na rozmowie kwalifikacyjnej z Javy? Zależy od firmy, a nawet od etapu rozmowy. Niektóre firmy pozwalają na AI na rozmowach technicznych albo wręcz go wymagają; wiele nadal go zabrania. Sprawdź to wcześniej u rekrutera. Jeśli AI jest dozwolone, sprawdzą, czy umiesz wyjaśnić i zweryfikować wygenerowany kod.
Która wersja Javy liczy się teraz na rozmowach? Aktualna wersja LTS to Java 25, wydana we wrześniu 2025 roku. Mimo to wiele firm nadal pracuje na Javie 17 i 21, więc warto wiedzieć, co wniosła każda z tych wersji.
Jakie zadania pojawiają się na live codingu z Javy? Zwykle małe zadania algorytmiczne na stringach, tablicach i kolekcjach: znajdź pierwszy niepowtarzający się znak, znajdź duplikaty w tablicy, sprawdź, czy słowo jest palindromem, pogrupuj dane za pomocą HashMap. Rekruter patrzy nie tylko na wynik, ale też na to, jak doprecyzowujesz wymagania, szacujesz złożoność i sprawdzasz przypadki brzegowe.
Jak szybko przygotować się do rozmowy kwalifikacyjnej z Javy? Trzy tygodnie wystarczą, żeby porządnie odświeżyć podstawy: tydzień pierwszy — Core Java i kolekcje, tydzień drugi — wielowątkowość i nowoczesna Java, tydzień trzeci — Spring, bazy danych i próbne rozmowy. Klucz to sprawdzać każdą odpowiedź kodem, zamiast ją wkuwać.
GO TO FULL VERSION