{
  "assessmentTests": {
    "java_test": {
      "name": "Test Java",
      "desc": "30 pytań scenariuszowych na temat podstawowej składni, OOP, kolekcji, generics, obsługi wyjątków i współbieżności — sprawdzić, czy twoja znajomość Java odpowiada temu, co pracodawcy rozumieją pod pojęciem biegłości w Java.",
      "recommendation": "Twój profil umiejętności Java",
      "results": {
        "beginner": {
          "name": "Początkujący",
          "desc": "Potrafisz pisać działające klasy i metody, ale pytania, które przegapiłeś, skupiają się wokół tożsamości i wartości domyślnych, a nie składni — String == kontra .equals, dlaczego new String(\"x\") nigdy nie ponownie używa puli stringów, czemu do wartości domyślnej pola numerycznego dochodzi inaczej niż dla pola wrapper. Nic z tego nie chodzi o bycie słabym w Java; to są konkretne reguły, które wprawiają w trudności ludzi, którzy nauczyli się języka przez próby i błędy zamiast ze zrozumienia, jak działa obsługa referencji i wartości prymitywne. Mają znaczenie w pracy, ponieważ każda z nich to miejsce, gdzie kod się kompiluje, działa i cicho robi złą rzecz.",
          "recommendation": "Zacznij od trzech rzeczy, w tej kolejności: dlaczego == dla dwóch obiektów String porównuje referencje, a nie znaki (i .equals jest tym, czego prawie zawsze chcesz), jak zawinięcie int przy overflow cicho zamiast wyrzucania wyjątku, i dlaczego niezainicjalizowane pole Integer domyślnie wynosi null, a pole int domyślnie wynosi 0. Oficjalne samouczki Java od Oracle i Baeldung obejmują wszystkie trzy z uruchomialnymi przykładami."
        },
        "intermediate": {
          "name": "Zaawansowany początkujący",
          "desc": "Komfortowo obsługujesz codzienny kod aplikacji — klasy, kolekcje, proste przepływy sterowania — i nie byłbyś spowolniony rutynową pracą nad cechami. Różnica między tym poziomem a Advanced dotyczy głównie tego, co dzieje się, gdy reguły Java wchodzą w interakcję ze współbieżnością i generics: metoda statyczna rozwiązana przez zadeklarowany typ zamiast obiektu, którego się spodziewałeś, kolejność iteracji HashMap, na którą cicho polegałeś, ConcurrentModificationException z usuwania elementu w pętli. To są takie błędy, które przechodzą szybki przegląd i pojawiają się tylko pod konkretnym warunkiem czasu wykonania.",
          "recommendation": "Skoncentruj się na tym, jak statyczny punkt widzenia kompilatora Twojego kodu różni się od tego, co się faktycznie wykonuje: rozwiązanie przeciążenia i ukrywanie metody statycznej przez zadeklarowany typ zamiast typu czasu wykonania, dlaczego HashMap nie daje gwarancji kolejności iteracji, i dlaczego modyfikowanie listy bezpośrednio podczas iteracji wyrzuca ConcurrentModificationException. Następnie generics erasure, ponieważ to wprawia w trudności ludzi, którzy już znają kolekcje indywidualnie."
        },
        "advanced": {
          "name": "Zaawansowany",
          "desc": "To jest poziom, który większość ogłoszeń o pracę rozumie pod pojęciem \"silna Java\". Czytasz klasę ze statycznymi blokami, blokami instancji i wieloma konstruktorami i potrafisz przewidzieć dokładną kolejność ich uruchomienia, wiesz dlaczego blok finally może cicho odrzucić wartość return bloku try, i sięgasz po try-with-resources zamiast ręcznego finally-close, ponieważ znasz gwarancję kolejności. To, co oddziela tę kategorię od szczytu, to współbieżna i interfejsowa strona pracy: co dokładnie blokuje synchronized, co gwarantuje volatile, i jak wyrażenia zmienności w interfejsach się rozwiązują.",
          "recommendation": "Wejdź w części chroniące kod, którym dotykają również inne wątki i inne interfejsy: różnica między tym, co blokuje metoda instancji synchronized kontra metoda statyczna synchronized, dlaczego volatile daje widoczność ale nie atomiczność dla counter++, i jak Java zmusza cię do ręcznego rozwiązania diamentu metody domyślnej. Materiały Baeldung i Java Concurrency in Practice na temat Java Memory Model to naturalny następny krok dla obu."
        },
        "expert": {
          "name": "Ekspert",
          "desc": "Uzyskałeś wyniki na górze każdej sekcji — podstawowa składnia i typy, OOP i zakres, kolekcje i generics, i wyjątki, współbieżność i idiomy. Praktycznie oznacza to, że możesz otrzymać obcą klasę i wyjaśnić, dlaczego błąd kompilacji, wyjątek czasu wykonania, lub cicho zła wartość się dzieje, a nie tylko to, co składnia mówi że powinna robić, co jest trudniejszą i bardziej wartościową umiejętnością. Na tym poziomie język sam w sobie rzadko jest czynnikiem ograniczającym; limit to zwykle projektowanie współbieżności lub kształt danych pod spodem.",
          "recommendation": "Zwroty są teraz w projektowaniu i diagnostyce: czytanie zrzutu wątków zamiast założenia że ma miejsce deadlock, wybór między synchronized, java.util.concurrent locks i atomics jako kompromis zamiast domyślnego podejścia, i projektowanie potoku Stream, które pozostaje leniwe celowo zamiast przez accident. Jeśli jesteś oceniany na stanowisko, opisz błąd współbieżności jak pominięta happens-before edge lub ConcurrentModificationException, który znalazłeś w produkcji zamiast wymieniania cech Java — to pokazuje rozumowanie, a nie tylko słownictwo."
        }
      },
      "questions": [
        {
          "question": "Tworzysz dwa obiekty String: String a = new String(\"cat\"); String b = new String(\"cat\"); Co oblicza a == b?",
          "options": [
            {
              "icon": "",
              "label": "true — literały String z tymi samymi znakami są zawsze tym samym obiektem"
            },
            {
              "icon": "",
              "label": "true — new String(...) ponownie wykorzystuje pulę stringów, więc identyczne teksty zawsze dzielą jeden obiekt"
            },
            {
              "icon": "",
              "label": "Błąd kompilacji — == nie może być używane do porównywania obiektów String"
            },
            {
              "icon": "",
              "label": "false — new String(...) zawsze alokuje nowy obiekt na heap, więc == porównuje dwie różne referencje, mimo że .equals(b) byłby zwracany true"
            }
          ]
        },
        {
          "question": "Integer x = 100; Integer y = 100; System.out.println(x == y); następnie Integer x2 = 200; Integer y2 = 200; System.out.println(x2 == y2); Co drukują te dwie linie?",
          "options": [
            {
              "icon": "",
              "label": "true następnie true — obiekty Integer zaboxowane są zawsze buforowane niezależnie od wartości"
            },
            {
              "icon": "",
              "label": "false następnie false — == na obiektach Integer to zawsze porównanie referencji, więc równe wartości nigdy się nie zgadzają"
            },
            {
              "icon": "",
              "label": "true następnie false, ale tylko dlatego, że 200 przepełnia byte — granica bufora jest niezwiązana z -128..127"
            },
            {
              "icon": "",
              "label": "true następnie false — wartości Integer zaboxowane z zakresu -128 do 127 są buforowane i udostępniane, więc 100 ponownie wykorzystuje jeden obiekt, ale 200 nie mieści się w buforze i zaboxowuje do dwóch oddzielnych obiektów"
            }
          ]
        },
        {
          "question": "int max = Integer.MAX_VALUE; System.out.println(max + 1); Co się dzieje?",
          "options": [
            {
              "icon": "",
              "label": "Wyrzuca ArithmeticException dla przepełnienia liczby całkowitej"
            },
            {
              "icon": "",
              "label": "Drukuje Integer.MAX_VALUE ponownie, ponieważ Java ogranicza maksimum typu"
            },
            {
              "icon": "",
              "label": "Drukuje Integer.MIN_VALUE — arytmetyka int cicho zawinięcia przy przepełnieniu zamiast wyrzucania"
            },
            {
              "icon": "",
              "label": "To jest błąd kompilacji — kompilator wykrywa przepełnienie z wyprzedzeniem"
            }
          ]
        },
        {
          "question": "System.out.println(0.1 + 0.2 == 0.3); Co to drukuje i dlaczego?",
          "options": [
            {
              "icon": "",
              "label": "false — 0.1, 0.2 i 0.3 nie mogą być reprezentowane dokładnie w binarnej zmiennoprzecinkowej, więc suma nosi błąd zaokrąglenia, który czyni ją nie bitową równą 0.3"
            },
            {
              "icon": "",
              "label": "true — Java zaokrągla arytmetykę double do najbliższej reprezentowanej liczby dziesiętnej przed porównaniem"
            },
            {
              "icon": "",
              "label": "true — dodawanie dwóch doubles jest zawsze dokładne dla wartości z dwoma miejscami dziesiętnymi"
            },
            {
              "icon": "",
              "label": "Wyrzuca wyjątek, ponieważ == nie jest zdefiniowany dla double w Java"
            }
          ]
        },
        {
          "question": "Klasa deklaruje dwa pola instancji bez inicjalizatora: int count; i Integer total; Przed uruchomieniem konstruktora, jakie są ich domyślne wartości?",
          "options": [
            {
              "icon": "",
              "label": "Oba domyślnie wynoszą 0, ponieważ Integer zaboxowuje do int podczas inicjalizacji pola"
            },
            {
              "icon": "",
              "label": "count wynosi 0 i total wynosi 0, zaboxowany automatycznie przy pierwszym odczytaniu"
            },
            {
              "icon": "",
              "label": "count wynosi 0 i total wynosi null — pola numeryczne prymitywne domyślnie wynoszą zero, ale niezainicjalizowane pole referencji wrapper domyślnie wynosi null jak każde inne pole obiektu"
            },
            {
              "icon": "",
              "label": "Oba domyślnie wynoszą null, aż zostaną jawnie przypisane, ponieważ Java nie ma niejawnych wartości domyślnych numerycznych"
            }
          ]
        },
        {
          "question": "Pętla uruchamia się 1000 razy, za każdym razem robiąc result += \"x\"; na String result. Co się faktycznie dzieje pod spodem każdej iteracji?",
          "options": [
            {
              "icon": "",
              "label": "Wewnętrzna tablica znaków istniejącego obiektu String jest rozszerzana na miejscu"
            },
            {
              "icon": "",
              "label": "Java automatycznie pakuje konkatenacje i alokuje tylko jeden ostateczny obiekt String"
            },
            {
              "icon": "",
              "label": "Kompiluje się do pojedynczego wywołania StringBuilder.append() udostępnionego przez wszystkie 1000 iteracji, bez dodatkowego obiektu alokowanego za iterację"
            },
            {
              "icon": "",
              "label": "Nowy obiekt String jest tworzony i result jest przypisywany aby wskazywał na niego — poprzedni obiekt String jest odrzucany, ponieważ String jest niezmienny i += nie może go modyfikować na miejscu"
            }
          ]
        },
        {
          "question": "final List<String> names = new ArrayList<>(); Które z tych jest prawdą?",
          "options": [
            {
              "icon": "",
              "label": "names.add(\"Ana\") się kompiluje i działa dobrze — final tylko zapobiega przepisaniu referencji names, nie mutowaniu obiektu, na który wskazuje"
            },
            {
              "icon": "",
              "label": "names.add(\"Ana\") jest błędem kompilacji, ponieważ final czyni niemodyfikowalną samą listę"
            },
            {
              "icon": "",
              "label": "Lista jest thread-safe dla równoczesnych zapisów, ponieważ została zadeklarowana final"
            },
            {
              "icon": "",
              "label": "final na zmiennej lokalnej nie ma efektu, chyba że typ jest również zadeklarowany niezmienny"
            }
          ]
        },
        {
          "question": "int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; System.out.println(a == b); System.out.println(Arrays.equals(a, b)); Co drukują te dwie linie?",
          "options": [
            {
              "icon": "",
              "label": "false następnie true — == porównuje referencje tablic (dwa różne obiekty tablicy), podczas gdy Arrays.equals porównuje elementy"
            },
            {
              "icon": "",
              "label": "true następnie true — tablice z identyczną zawartością to ten sam obiekt w Java"
            },
            {
              "icon": "",
              "label": "false następnie false — Arrays.equals działa tylko dla tablic obiektów, a nie dla prymitywnych tablic int"
            },
            {
              "icon": "",
              "label": "true następnie false — == na tablicach porównuje zawartość, i Arrays.equals jest zbędne"
            }
          ]
        },
        {
          "question": "void show(Object o) { print(\"Object\"); } void show(String s) { print(\"String\"); } Object ref = \"hello\"; show(ref); Które przeciążenie działa i dlaczego?",
          "options": [
            {
              "icon": "",
              "label": "show(String) działa, ponieważ Java sprawdza rzeczywistą klasę czasu wykonania obiektu przed wyborem przeciążenia"
            },
            {
              "icon": "",
              "label": "show(Object) działa — rozwiązanie przeciążenia decyduje się w czasie kompilacji używając zadeklarowanego typu zmiennej, a nie rzeczywistego typu czasu wykonania obiektu, do którego się odnosi"
            },
            {
              "icon": "",
              "label": "To jest błąd kompilacji — Object nie może być przesłany gdzie istnieje bardziej specyficzne przeciążenie"
            },
            {
              "icon": "",
              "label": "Obie metody działają, po jednej, ponieważ Java rozwiązuje przeciążenia próbując każdego dopasowania"
            }
          ]
        },
        {
          "question": "Klasa Base ma static void greet() { print(\"Base\"); }. Klasa Derived rozszerza Base i również deklaruje static void greet() { print(\"Derived\"); }. Piszesz: Base ref = new Derived(); ref.greet(); Co się drukuje?",
          "options": [
            {
              "icon": "",
              "label": "Derived — metody statyczne override dokładnie jak metody instancji, następując rzeczywisty typ obiektu czasu wykonania"
            },
            {
              "icon": "",
              "label": "To jest błąd kompilacji — metody statyczne nie mogą być wywoływane przez referencję instancji"
            },
            {
              "icon": "",
              "label": "Base — metody statyczne nie są polimorficzne; wywołanie jednej przez referencję rozwiązuje się przez zadeklarowany typ referencji w czasie kompilacji, a nie rzeczywisty typ obiektu"
            },
            {
              "icon": "",
              "label": "Zarówno Base jak i Derived drukują, ponieważ wywołanie rozwiązuje się do ukrytej i ukrywającej wersji"
            }
          ]
        },
        {
          "question": "Wewnątrz metody piszesz int count = 0; następnie próbujesz odwołać się do count z wnętrza lambda przekazanej do innej metody. Co musi być prawdą o count, aby się skompilowało?",
          "options": [
            {
              "icon": "",
              "label": "count musi być efektywnie final — nigdy nie przepisany nigdzie po jego wartości początkowej — ponieważ lambda przechwytuje migawkę, a nie żywą referencję do zmiennej lokalnej mutable"
            },
            {
              "icon": "",
              "label": "Nic — każda zmienna lokalna może być swobodnie czytana i przepisywana z wnętrza lambda"
            },
            {
              "icon": "",
              "label": "count musi być zadeklarowany volatile aby lambda zawsze widziała jego najnowszą wartość"
            },
            {
              "icon": "",
              "label": "count musi być polem, a nie zmienną lokalną — lambdy nie mogą przechwytywać lokalnych w ogóle"
            }
          ]
        },
        {
          "question": "void rename(StringBuilder sb) { sb = new StringBuilder(\"new\"); } jest wywoływana jako StringBuilder original = new StringBuilder(\"old\"); rename(original); Co jest original po wywołaniu?",
          "options": [
            {
              "icon": "",
              "label": "Staje się \"new\" — obiekty są przesyłane przez referencję w Java, więc przepisanie parametru również zmienia zmienną rozmówcy"
            },
            {
              "icon": "",
              "label": "Staje się \"new\" tylko dla mutable typów jak StringBuilder, ale nie dla immutable typów"
            },
            {
              "icon": "",
              "label": "Pozostaje \"old\" — Java przesyła samą referencję przez wartość, więc przepisanie parametru wewnątrz metody tylko zmienia kopia lokalna referencji, pozostawiając oryginalną rozmówcy niezmienioną"
            },
            {
              "icon": "",
              "label": "Wyrzuca wyjątek czasu wykonania, ponieważ sb został przepisany wewnątrz metody"
            }
          ]
        },
        {
          "question": "Klasa ma blok inicjalizatora statycznego, blok inicjalizatora instancji i konstruktor, w tej kolejności źródła. Tworzysz dwa obiekty tej klasy jeden za drugim. W jakiej kolejności się one uruchamiają?",
          "options": [
            {
              "icon": "",
              "label": "Blok statyczny uruchamia się dokładnie raz, przy pierwszym załadowaniu klasy; następnie dla każdego obiektu, blok instancji uruchamia się i następnie uruchamia się konstruktor"
            },
            {
              "icon": "",
              "label": "Wszystkie trzy uruchamiają się na nowo, w kolejności źródła, dla każdego tworzonego obiektu"
            },
            {
              "icon": "",
              "label": "Konstruktor uruchamia się pierwszy dla każdego obiektu, następnie blok instancji, następnie blok statyczny raz na samym końcu"
            },
            {
              "icon": "",
              "label": "Blok statyczny uruchamia się raz na obiekt, tuż przed blokiem instancji"
            }
          ]
        },
        {
          "question": "Klasa ma void log(String s) i void log(String... args). Wywoływujesz log(\"hi\"). Które się uruchamia?",
          "options": [
            {
              "icon": "",
              "label": "log(String... args) — przeciążenia varargs są zawsze preferowane gdy oba mają zastosowanie"
            },
            {
              "icon": "",
              "label": "To jest błąd kompilacji — wywołanie jest niewyraźne między dwoma przeciążeniami"
            },
            {
              "icon": "",
              "label": "log(String s) — gdy przeciążenie stałej arności dokładnie pasuje, Java zawsze je preferuje nad przeciążeniem varargs, które jest używane tylko jako ostatnia deska ratunku"
            },
            {
              "icon": "",
              "label": "Cokolwiek jest zadeklarowane pierwsze w pliku źródłowym uruchamia się"
            }
          ]
        },
        {
          "question": "Pierwsza linia konstruktora wywołuje this(0); aby delegować do innego konstruktora w tej samej klasie. Gdzie to jest dozwolone pojawić się?",
          "options": [
            {
              "icon": "",
              "label": "Gdziekolwiek w treści konstruktora, dopóki uruchamia się przed zwróceniem obiektu"
            },
            {
              "icon": "",
              "label": "Tylko jako pierwszy dokładnie statement konstruktora — this() (lub super()) musi być pierwszą linią, i konstruktor nie może wywoływać zarówno this() jak i super()"
            },
            {
              "icon": "",
              "label": "Tylko jako ostatni statement, po całej inicjalizacji pola"
            },
            {
              "icon": "",
              "label": "Tylko w konstruktorach wyraźnie oznaczonych jako delegujących, używając słowa kluczowego delegate"
            }
          ]
        },
        {
          "question": "Potrzebujesz listy, która będzie mieć elementy wstawiane na przodzie bardzo często, i losowe dostępy czytania są rzadkie. Które jest lepszym strukturalnym dopasowaniem, i dlaczego?",
          "options": [
            {
              "icon": "",
              "label": "ArrayList — jego ciągła tablica wspierająca czyni każdą operację, włączając wstawienie przodu, szybszą niż struktura połączona"
            },
            {
              "icon": "",
              "label": "Działają identycznie, ponieważ oba implementują interfejs List z tymi samymi gwarancjami czasu"
            },
            {
              "icon": "",
              "label": "LinkedList — wstawienie na przodzie to O(1) ponieważ po prostu relinkowuje węzeł, podczas gdy ArrayList musi przesunąć każdy istniejący element w górę o jeden, czyniąc wstawienie przodu O(n)"
            },
            {
              "icon": "",
              "label": "LinkedList, ponieważ wspiera losowy dostęp w O(1) podczas gdy ArrayList nie"
            }
          ]
        },
        {
          "question": "Wstawiasz pięć wpisów do zwykłej HashMap w konkretnej kolejności, następnie iterujesz je z pętlą for-each. W jakiej kolejności wpisów wychodzą?",
          "options": [
            {
              "icon": "",
              "label": "Tej samej kolejności, w jakiej wpisy zostały wstawione, ponieważ mapy Java zawsze zachowują kolejność wstawienia"
            },
            {
              "icon": "",
              "label": "Brak gwarantowanej kolejności — kolejność iteracji HashMap zależy od umieszczenia w koszyku hasha, a nie kolejności wstawienia, i może nawet zmienić się między przebiegami; LinkedHashMap to co zachowuje kolejność wstawienia"
            },
            {
              "icon": "",
              "label": "Posortowane przez klucz automatycznie, tym samym sposobem jak TreeMap się zachowuje"
            },
            {
              "icon": "",
              "label": "Odwrotna kolejność wstawienia, ponieważ HashMap wewnętrznie używa stosu"
            }
          ]
        },
        {
          "question": "Ile null kluczy może zwykła java.util.HashMap przechowywać jednocześnie, i ile null wartości?",
          "options": [
            {
              "icon": "",
              "label": "Brak null kluczy i brak null wartości są kiedykolwiek dozwolone w żadnej implementacji Map"
            },
            {
              "icon": "",
              "label": "Co najwyżej jeden null klucz, i dowolna liczba null wartości — HashMap pozwala na jeden null klucz, w odróżnieniu od Hashtable, który nie pozwala na żaden"
            },
            {
              "icon": "",
              "label": "Nieograniczone null klucze i nieograniczone null wartości, ponieważ null jest traktowany jak każdy inny klucz"
            },
            {
              "icon": "",
              "label": "Jeden null klucz i maksymalnie jedna null wartość, oba ograniczone do jednego"
            }
          ]
        },
        {
          "question": "Iterujesz List z pętlą for-each i wywoływujesz list.remove(item) bezpośrednio na liście z wnętrza treści pętli, na niektórych ale nie wszystkich elementach. Co się dzieje?",
          "options": [
            {
              "icon": "",
              "label": "Działa poprawnie i usuwa dokładnie zamierzone elementy"
            },
            {
              "icon": "",
              "label": "Cicho pomija element po usuniętym, ale inaczej kompletuje się bez błędu"
            },
            {
              "icon": "",
              "label": "Wyrzuca IndexOutOfBoundsException gdy pętla osiąga starą wielkość listy"
            },
            {
              "icon": "",
              "label": "Wyrzuca ConcurrentModificationException — modyfikowanie struktury listy bezpośrednio podczas gdy ukryty iterator ją przechodzi jest wykrywane i odrzucane; Iterator.remove() musi być używane zamiast tego"
            }
          ]
        },
        {
          "question": "W czasie wykonania, biorąc List<String> list, co faktycznie możesz określić o jego parametrze typu generic poprzez refleksję lub instanceof?",
          "options": [
            {
              "icon": "",
              "label": "Możesz wywołać list.getElementType() aby pobrać String.class w czasie wykonania"
            },
            {
              "icon": "",
              "label": "instanceof List<String> się kompiluje i poprawnie sprawdza typ elementu"
            },
            {
              "icon": "",
              "label": "JVM przechowuje parametr typu jako ukryte metadane dostępne poprzez list.getGenericType()"
            },
            {
              "icon": "",
              "label": "Nic — informacje o typie generic są wymazane w czasie kompilacji, więc w czasie wykonania obiekt jest po prostu List, i nie ma sposobu aby odzyskać czy został zadeklarowany List<String> czy List<Integer>"
            }
          ]
        },
        {
          "question": "switch (day) { case 1: case 2: print(\"Weekday\"); break; case 6: print(\"Saturday\"); case 7: print(\"Sunday\"); break; default: print(\"?\"); } Jeśli day wynosi 6, co się drukuje?",
          "options": [
            {
              "icon": "",
              "label": "Tylko Saturday — każdy blok case w switch zawsze się zatrzymuje po własnym print statement"
            },
            {
              "icon": "",
              "label": "Tylko Sunday — dopasowanie zaczyna się w case 6 ale tylko ostatnia pasująca etykieta przed break się wykonuje"
            },
            {
              "icon": "",
              "label": "Nic się nie drukuje, ponieważ day 6 nie ma pasującego case z własnym break bezpośrednio pod nim"
            },
            {
              "icon": "",
              "label": "Saturday następnie Sunday — case 6 nie ma break, więc wykonanie pada do kodu następnego case przed trafieniem następującego break"
            }
          ]
        },
        {
          "question": "Klasa Product potrzebuje pojedynczego, oczywistego \"naturalnego\" porządku sortowania po cenie, plus możliwości też sortowania po nazwie lub po poziomie zapasu w różnych miejscach w codebase. Które połączenie to właściwy projekt?",
          "options": [
            {
              "icon": "",
              "label": "Implementuj Comparable<Product> trzy osobne razy, jeden na porządek, i pozwól rozmówcy wybrać które compareTo uruchamia się"
            },
            {
              "icon": "",
              "label": "Implementuj Comparable<Product> dla naturalnego porządku ceny, i pisz osobne instancje Comparator<Product> dla porządków nazwy i poziomu zapasu używanych w innych miejscach"
            },
            {
              "icon": "",
              "label": "Używaj tylko Comparator dla każdego porządku, włączając cenę, ponieważ Comparable nie ma tutaj przewagi"
            },
            {
              "icon": "",
              "label": "Używaj tylko Comparable poprzez dodawanie trzech przeciążonych metod compareTo, jedna za porządek"
            }
          ]
        },
        {
          "question": "Metoda wywołuje new FileReader(path), która deklaruje throws IOException. IOException rozszerza Exception, a nie RuntimeException. Co musisz zrobić aby to się skompilowało?",
          "options": [
            {
              "icon": "",
              "label": "Nic — kompilator wymusza to tylko dla wyjątków rozszerzających RuntimeException"
            },
            {
              "icon": "",
              "label": "Albo złap IOException w try/catch albo deklaruj throws IOException na swojej własnej metodzie — checked wyjątki muszą być obsługiwane lub propagowane wyraźnie, w odróżnieniu od unchecked RuntimeException podklas"
            },
            {
              "icon": "",
              "label": "Zawij wywołanie w try/catch dla RuntimeException, ponieważ IOException jest automatycznie unchecked w nowoczesnym Java"
            },
            {
              "icon": "",
              "label": "Deklaruj metodę jako static — metody statyczne są zwolnione z obsługi checked wyjątków"
            }
          ]
        },
        {
          "question": "try (Resource a = new Resource(\"A\"); Resource b = new Resource(\"B\")) { ... } używa dwóch zasobów implementujących AutoCloseable. Jeśli blok try kończy się normalnie, w jakiej kolejności się zamykają?",
          "options": [
            {
              "icon": "",
              "label": "A się zamyka najpierw, następnie B, dopasowując kolejność deklaracji"
            },
            {
              "icon": "",
              "label": "B się zamyka pierwszy, następnie A — try-with-resources zamyka zasoby w odwrotnej kolejności niż były zadeklarowane"
            },
            {
              "icon": "",
              "label": "Oboje zamykają się jednocześnie, ponieważ try-with-resources parallelizuje czyszczenie"
            },
            {
              "icon": "",
              "label": "Tylko B się zamyka automatycznie — A musi być jeszcze zamknięte ręcznie w bloku finally"
            }
          ]
        },
        {
          "question": "int getValue() { try { return 1; } finally { return 2; } } Co zwraca getValue()?",
          "options": [
            {
              "icon": "",
              "label": "1 — wartość return bloku try jest już zatwierdzona zanim finally uruchamia się, więc finally nie może jej zmienić"
            },
            {
              "icon": "",
              "label": "Wyrzuca wyjątek w czasie wykonania, ponieważ metoda nie może zwrócić z dwóch miejsc"
            },
            {
              "icon": "",
              "label": "2 — statement return wewnątrz finally override i zastępuje każdy return już w postępie z bloku try, odrzucając wartość 1 całkowicie"
            },
            {
              "icon": "",
              "label": "To jest błąd kompilacji — finally nie jest dozwolony zawierać statement return"
            }
          ]
        },
        {
          "question": "try { ... } catch (IOException e) { ... } catch (FileNotFoundException e) { ... }, i FileNotFoundException rozszerza IOException. Co się dzieje gdy próbujesz to skompilować?",
          "options": [
            {
              "icon": "",
              "label": "Błąd kompilacji — blok catch FileNotFoundException jest niedostępny ponieważ wcześniejszy, bardziej ogólny blok catch IOException już dopasowuje każdy FileNotFoundException"
            },
            {
              "icon": "",
              "label": "Się kompiluje dobrze, i bardziej specyficzny blok FileNotFoundException uruchamia się gdy ten dokładny typ jest wyrzucany"
            },
            {
              "icon": "",
              "label": "Się kompiluje dobrze, i oba catch bloki uruchamiają się w kolejności dla FileNotFoundException"
            },
            {
              "icon": "",
              "label": "Jest dobrze w czasie kompilacji ale wyrzuca błąd czasu wykonania przy pierwszym rzeczywistym pojawieniu się FileNotFoundException"
            }
          ]
        },
        {
          "question": "Klasa ma synchronized metodę instancji process() i synchronized metodę statyczną configure(). Co dokładnie każdy z nich blokuje?",
          "options": [
            {
              "icon": "",
              "label": "process() blokuje monitor konkretnego obiektu instancji na którym jest wywoływany, podczas gdy configure() blokuje monitor obiektu Class samego — udostępnianego przez każdą instancję"
            },
            {
              "icon": "",
              "label": "Oboje blokują ten sam pojedynczy globalny lock dla całej JVM, niezależnie od instancji czy klasy"
            },
            {
              "icon": "",
              "label": "process() blokuje obiekt Class, i configure() blokuje która instancja go wywoła"
            },
            {
              "icon": "",
              "label": "Żaden faktycznie nie blokuje nic, chyba że synchronized blok jest również używany wewnątrz treści metody"
            }
          ]
        },
        {
          "question": "Pole jest deklarowane volatile int counter = 0;, i wielkie wątki uruchamiają counter++ na tym równocześnie. Czy volatile zapobiega utracie aktualizacji tutaj?",
          "options": [
            {
              "icon": "",
              "label": "Tak — volatile czyni każdą operację na polu atomic, włączając inkrementacje"
            },
            {
              "icon": "",
              "label": "Nie — volatile gwarantuje tylko że czytania widzą ostatni zapis przesyłany między wątkami (widoczność); counter++ jest czytaniem-modyfikowaniem-pisaniem z wieloma krokami, i volatile nic nie robi aby uczynić te kroki atomic"
            },
            {
              "icon": "",
              "label": "Tak, ale tylko dla int i long pól specjalnie, ze względu na jak JVM obsługuje wartości 64-bitowe"
            },
            {
              "icon": "",
              "label": "Nie, i volatile również nie gwarantuje widoczności dla typów prymitywnych jak int"
            }
          ]
        },
        {
          "question": "Interfejs A i interfejs B każdy deklarują metodę domyślną describe(). Klasa implementuje zarówno A jak i B i nie override describe() sama. Co się dzieje?",
          "options": [
            {
              "icon": "",
              "label": "Kompilator automatycznie wybie wersję interfejsu A, ponieważ jest wymieniony pierwszy w klauzuli implements"
            },
            {
              "icon": "",
              "label": "Obie wersje uruchamiają się, jedna za drugą, za każdym razem gdy describe() jest wywoływana"
            },
            {
              "icon": "",
              "label": "Jest dobrze w czasie kompilacji, ale wyrzuca AmbiguousMethodException przy pierwszym opisie() wywoływanym"
            },
            {
              "icon": "",
              "label": "Błąd kompilacji — gdy dwa interfejsy przyczyniają się taką samą metodę domyślną, implementująca klasa musi ją sama override aby rozwiązać niewyraźność, ponieważ Java nie będzie się domyślać, którą miałeś na myśli"
            }
          ]
        },
        {
          "question": "list.stream().filter(x -> x > 0).map(x -> x * 2); jest napisane ale wynik nigdy nie jest przypisywany do terminalnej operacji jak .collect() lub .forEach(). Co faktycznie się dzieje gdy ta linia się wykonuje?",
          "options": [
            {
              "icon": "",
              "label": "Nic się nie dzieje elementom listy — filter i map to leniwe operacje pośrednie, które tylko budują opis potoku; bez terminalnej operacji, żaden z tego potoku nigdy się nie wykonuje"
            },
            {
              "icon": "",
              "label": "Każdy element jest natychmiast filtrowany i mapowany, dokładnie tak jakby terminalna operacja była wywoływana"
            },
            {
              "icon": "",
              "label": "Tylko filter uruchamia się natychmiast; map jest odroczony aż do pojawienia się terminalna operacja"
            },
            {
              "icon": "",
              "label": "Wyrzuca IllegalStateException, ponieważ potok Stream wymaga terminalnej operacji aby się skompilować"
            }
          ]
        }
      ],
      "optionOrderVersion": "0154f9576054ad6f"
    }
  }
}
