{
  "assessmentTests": {
    "java_test": {
      "name": "Java-test",
      "desc": "30 scenariofrågor om kärnor syntaxtyper, OOP-mekanik, samlingar, generiska, undantag och samtidighet — ta reda på om din Java överensstämmer med vad en jobbannonering menar med Java-kompetens.",
      "recommendation": "Din Java-kompetensprofil",
      "results": {
        "beginner": {
          "name": "Nybörjare",
          "desc": "Du kan skriva fungerade klasser och metoder, men frågorna du missade grupperas kring identitet och standardvärden snarare än syntax — String == vs .equals(), varför new String(\"x\") aldrig återanvänder strängpoolen, vad ett numeriskt fält standardvärderas till jämfört med ett wrapper-fält. Inget av detta handlar om att vara dålig på Java; dessa är de specifika regler som stoppar människor som lärt sig språket genom försök och misstag snarare än från hur referenser och primitiva faktiskt fungerar under huven. De spelar roll på jobbet eftersom var och en är där kod kompilerar, körs och tyst gör något fel.",
          "recommendation": "Börja med tre saker, i denna ordning: varför == på två String-objekt jämför referenser, inte tecken (och .equals är vad du nästan alltid vill), hur int-överflöde lindas tyst istället för att kasta, och varför ett oinitialiserat Integer-fält standardvärderas till null medan ett int-fält standardvärderas till 0. Oracles officiella Java-handledningar och Baeldung täcker alla tre med körbara exempel."
        },
        "intermediate": {
          "name": "Medelnivå",
          "desc": "Du hanterar vardaglig programkod bekvämt — klasser, samlingar, enkel kontrollflöde — och skulle inte bromsas ned av rutinmässig funktionsutveckling. Gapet mellan här och Avancerad handlar mestadels om vad som händer när Javas regler interagerar med samtidighet och generiska: en statisk metod löst av deklarerad typ istället för objektet du förväntade dig, en HashMap-iterationsordning du tyst förlitade dig på, en ConcurrentModificationException från att ta bort ett objekt mitt i slinga. Dessa är de slag av buggar som passerar en snabb genomläsning och bara visar sig under ett specifikt körningsvillkor.",
          "recommendation": "Fokusera på hur kompilatorns statiska syn på din kod skiljer sig från vad som körs: överbelastningsupplösning och statisk-metoddöljning av deklarerad typ snarare än körningstyp, varför HashMap inte garanterar iterationsordning, och varför ändrande av en lista direkt vid iterering kastar ConcurrentModificationException. Sedan generiska borttagning, eftersom det stoppar människor som redan vet samlingar individuellt."
        },
        "advanced": {
          "name": "Avancerad",
          "desc": "Detta är nivån som de flesta jobbannonseringar menar med \"stark Java.\" Du läser en klass med statiska block, instansblock och flera konstruktorer och kan förutsäga den exakta ordningen de körs i, du vet varför en finally-block tyst kan förkasta ett try-blocks returvärde, och du når för try-with-resources istället för en manuell finally-close eftersom du vet den beställningsgaranti den ger dig. Vad skiljer detta band från toppen är den samtidiga och interface-nivå-sidan av arbetet: vad synchronized faktiskt låser, vad volatile gör och inte garanterar, och hur default-method-konflikter löses.",
          "recommendation": "Pusha in i de delar som skyddar kod som andra trådar och andra interface också rör: skillnaden mellan vad en synchronized-instansmetod låser jämfört med en synchronized-statisk-metod, varför volatile ger synlighet men inte atomicitet för counter++, och hur Java tvingar dig att lösa en default-method-diamant för hand. Baeldungs och Java Concurrency in Practice:s material om Java Memory Model är det naturliga nästa steget för båda."
        },
        "expert": {
          "name": "Expert",
          "desc": "Du fick toppresultat i varje sektion — kärnor syntaxtyper och typer, OOP-mekanik och omfång, samlingar och generiska, och undantag, samtidighet och idiomer. Praktiskt sett betyder det att du kan få en främlings klass och förklara varför ett kompileringsfel, ett körtidsundantag, eller ett tyst felaktigt värde händer, inte bara vad syntaxen säger att det borde göra, vilket är den svårare och mer värdefulla färdigheten. På denna nivå är språket själv sällan den begränsande faktorn; gränsen är vanligtvis samtidighetsdesign eller formen på data under den.",
          "recommendation": "Avkastningen är nu i design och diagnos: läsning av en thread dump innan du antar att ett hängande är ett dödläge, väljande mellan synchronized, java.util.concurrent-lås och atomics som en avvägning snarare än som en standard, och stream-pipeline-design som stannar lazy med vilje snarare än av en slump. Om du screenas för en roll, beskriva en samtidighetsbug som en missad happens-before-kant eller en ConcurrentModificationException du hittade i produktion snarare än att namnge Java-funktioner — det visar resonemanget, inte bara vokabulären."
        }
      },
      "questions": [
        {
          "question": "Du skapar två String-objekt: String a = new String(\"cat\"); String b = new String(\"cat\"); Vad evalueras a == b till?",
          "options": [
            {
              "icon": "",
              "label": "true — strängbokstäver med samma tecken är alltid samma objekt"
            },
            {
              "icon": "",
              "label": "true — new String(...) återanvänder strängpoolen, så identisk text delar alltid ett objekt"
            },
            {
              "icon": "",
              "label": "Ett kompileringsfel — == kan inte användas för att jämföra String-objekt"
            },
            {
              "icon": "",
              "label": "false — new String(...) allokerar alltid ett nytt objekt på högen, så == jämför två olika referenser även om .equals(b) skulle returnera true"
            }
          ]
        },
        {
          "question": "Integer x = 100; Integer y = 100; System.out.println(x == y); sedan Integer x2 = 200; Integer y2 = 200; System.out.println(x2 == y2); Vad skriver de två raderna ut?",
          "options": [
            {
              "icon": "",
              "label": "true sedan true — autoboxade Integer-objekt är alltid cachade oavsett värde"
            },
            {
              "icon": "",
              "label": "false sedan false — == på Integer-objekt är alltid en referensjämförelse, så lika värden matchas aldrig"
            },
            {
              "icon": "",
              "label": "true sedan false, men bara för att 200 överflödar en byte — cache-gränsen är orelaterad till -128..127"
            },
            {
              "icon": "",
              "label": "true sedan false — autoboxade Integer-värden från -128 till 127 cacheas och delas, så 100 återanvänder ett objekt, men 200 faller utanför cache och autoboxas till två separata objekt"
            }
          ]
        },
        {
          "question": "int max = Integer.MAX_VALUE; System.out.println(max + 1); Vad händer?",
          "options": [
            {
              "icon": "",
              "label": "Det kastar ett ArithmeticException för heltalöverflöde"
            },
            {
              "icon": "",
              "label": "Det skriver ut Integer.MAX_VALUE igen, för att Java fixar på typens maximalt"
            },
            {
              "icon": "",
              "label": "Det skriver ut Integer.MIN_VALUE — int-aritmetik lindas tyst omkring vid överflöde istället för att kasta"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel — kompilatorn detekterar överflödet i förväg"
            }
          ]
        },
        {
          "question": "System.out.println(0.1 + 0.2 == 0.3); Vad skriver detta ut och varför?",
          "options": [
            {
              "icon": "",
              "label": "false — 0.1, 0.2 och 0.3 kan inte representeras exakt i binär floating-point, så summan bär avrundningsfel som gör den inte bitvis-för-bitvis lika med 0.3"
            },
            {
              "icon": "",
              "label": "true — Java rundar double-aritmetik till närmaste representerbara decimal innan jämförelse"
            },
            {
              "icon": "",
              "label": "true — IEEE 754 garanterar att 0.1 + 0.2 är exakt lika med 0.3"
            },
            {
              "icon": "",
              "label": "Det beror på JVM-implementationen"
            }
          ]
        },
        {
          "question": "En klass deklarerar två instansfält utan initierare: int count; Integer wrapped; — vad är deras standardvärden?",
          "options": [
            {
              "icon": "",
              "label": "Båda är 0"
            },
            {
              "icon": "",
              "label": "Båda är null"
            },
            {
              "icon": "",
              "label": "count är 0, wrapped är null — primitiva fält får sitt primitiva standardvärde, wrapper-typ-fält får null"
            },
            {
              "icon": "",
              "label": "Båda är oinitialiserade; läsning av dem är ett kompileringsfel"
            }
          ]
        },
        {
          "question": "En slinga körs 1000 gånger, varje gång gör result += \"x\"; på en StringBuilder. Vad är problemet?",
          "options": [
            {
              "icon": "",
              "label": "Inget — += är en effektiv operation"
            },
            {
              "icon": "",
              "label": "result += \"x\" skapar en ny StringBuilder varje iteration, så komplexiteten är O(n²) istället för O(n)"
            },
            {
              "icon": "",
              "label": "StringBuilder kan inte lagra 1000 tecken"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel"
            }
          ]
        },
        {
          "question": "final List<String> names = new ArrayList<>(); Vilka av dessa kan du göra med names?",
          "options": [
            {
              "icon": "",
              "label": "Inget — final betyder att variabeln aldrig kan ändras"
            },
            {
              "icon": "",
              "label": "Du kan lägga till eller ta bort element från listan (names.add(), names.remove()), men du kan inte ändra själva referenser (names = new ArrayList()) — final låser referensen, inte objektet"
            },
            {
              "icon": "",
              "label": "Du kan bara läsa från listan"
            },
            {
              "icon": "",
              "label": "Det beror på vilka element listan innehåller"
            }
          ]
        },
        {
          "question": "int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; System.out.println(a == b); Vad skrivs ut?",
          "options": [
            {
              "icon": "",
              "label": "true — arrayerna har samma innehål"
            },
            {
              "icon": "",
              "label": "false — arrays jämförs efter referens, inte innehål; detta är två separata objekt på högen"
            },
            {
              "icon": "",
              "label": "true, men bara för primitiva arrays; objekt-arrays jämförs efter referens"
            },
            {
              "icon": "",
              "label": "Ett kompileringsfel"
            }
          ]
        },
        {
          "question": "void show(Object o) { print(\"Object\"); } void show(String s) { print(\"String\"); } Du kallar show(\"text\"); Vilken kallas?",
          "options": [
            {
              "icon": "",
              "label": "show(Object o) — Object är mer allmän"
            },
            {
              "icon": "",
              "label": "show(String s) — kompilatorn väljer den mest specifika matchningen"
            },
            {
              "icon": "",
              "label": "Båda kallas"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel på grund av tvetydighet"
            }
          ]
        },
        {
          "question": "Class Base har static void greet() { print(\"Base\"); }. Class Child extends Base { static void greet() { print(\"Child\"); } } Du kallar Child.greet(); Vad skrivs ut?",
          "options": [
            {
              "icon": "",
              "label": "Base — statiska metoder är ärvda"
            },
            {
              "icon": "",
              "label": "Child — den statiska metoden är dold (skuggad) av Child-versionen"
            },
            {
              "icon": "",
              "label": "Båda Base och Child"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel — du kan inte åsidosätta statiska metoder"
            }
          ]
        },
        {
          "question": "Inuti en metod, du skriver int count = 0; sedan försöker du läsa count från en inre klassdefinierad inuti samma metod. Vad måste true om count?",
          "options": [
            {
              "icon": "",
              "label": "Inget — variabeln är tillgänglig"
            },
            {
              "icon": "",
              "label": "Det måste deklareras final (eller effektivt final — aldrig åter tilldelat) för att den inre klassen ska kunna se det"
            },
            {
              "icon": "",
              "label": "Det måste deklareras static"
            },
            {
              "icon": "",
              "label": "Det är omöjligt — inre klasser kan inte få åtkomst till lokala variabler"
            }
          ]
        },
        {
          "question": "void rename(StringBuilder sb) { sb = new StringBuilder(\"new\"); } Du kallar rename(myBuilder); — vad händer med myBuilder?",
          "options": [
            {
              "icon": "",
              "label": "Den får nytt innehål \"new\""
            },
            {
              "icon": "",
              "label": "Den är oförändrad — sb = ... ändrar enbart den lokala parametervariabeln, inte det objekt som ursprungligen skickades"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel"
            },
            {
              "icon": "",
              "label": "myBuilder blir null"
            }
          ]
        },
        {
          "question": "En klass har en statisk initierare-block, ett instans-initierare-block, och en konstruktor. I vilken ordning körs de när du skapar ett objekt?",
          "options": [
            {
              "icon": "",
              "label": "Konstruktor, sedan instans-block, sedan statisk-block"
            },
            {
              "icon": "",
              "label": "Statisk-block (en gång när klassen laddar), sedan instans-block (varje objekt), sedan konstruktor"
            },
            {
              "icon": "",
              "label": "Instans-block, sedan konstruktor, sedan statisk-block"
            },
            {
              "icon": "",
              "label": "De körs alla parallellt"
            }
          ]
        },
        {
          "question": "En klass har void log(String s) och void log(String... args). Du kallar log(\"text\"); Vilken kallas?",
          "options": [
            {
              "icon": "",
              "label": "Båda kallas"
            },
            {
              "icon": "",
              "label": "log(String s) — varargs är mindre föredragna; en exakt matchning är alltid föredraget"
            },
            {
              "icon": "",
              "label": "log(String... args) — varargs är mer flexibel"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel på grund av tvetydighet"
            }
          ]
        },
        {
          "question": "En konstruktors första rad kallar this(0); för att delegera till en annan konstruktor. Kan this call ha instansfältvärden tillgängliga?",
          "options": [
            {
              "icon": "",
              "label": "Ja — instansfält är alltid tillgängliga"
            },
            {
              "icon": "",
              "label": "Nej — this() måste vara den första satsen, innan någon instansinitiering händer"
            },
            {
              "icon": "",
              "label": "Bara om de är markerade static"
            },
            {
              "icon": "",
              "label": "Bara om de är markerade final"
            }
          ]
        },
        {
          "question": "Du behöver en lista som kommer att ha element insatta vid framsidan ofta. ArrayList eller LinkedList?",
          "options": [
            {
              "icon": "",
              "label": "ArrayList — det är alltid snabbare"
            },
            {
              "icon": "",
              "label": "LinkedList — infogning vid framsidan är O(1); ArrayList måste flytta alla befintliga element, O(n)"
            },
            {
              "icon": "",
              "label": "Ingen skillnad för små listor"
            },
            {
              "icon": "",
              "label": "Det beror på elementtypen"
            }
          ]
        },
        {
          "question": "Du infogar fem poster i en vanlig HashMap i en specifik ordning. Iterera senare — kommer iterationsordningen att matcha infogningsordningen?",
          "options": [
            {
              "icon": "",
              "label": "Ja — HashMap bevarar infogningsordning"
            },
            {
              "icon": "",
              "label": "Nej — HashMap ger ingen iterationsordningsgaranti; ordningen beror på hashkoder och interna omstorlekar"
            },
            {
              "icon": "",
              "label": "Ja, men bara på vissa JVM-versioner"
            },
            {
              "icon": "",
              "label": "Du behöver LinkedHashMap för att garantera infogningsordning"
            }
          ]
        },
        {
          "question": "Hur många null-nycklar kan en vanlig java.util.HashMap hålla på samma gång?",
          "options": [
            {
              "icon": "",
              "label": "Noll — null är inte en giltig nyckel"
            },
            {
              "icon": "",
              "label": "En — HashMap behandlar null som en giltig nyckel, men bara en null-nyckel är tillåten (ungefär som en unik nyckel)"
            },
            {
              "icon": "",
              "label": "Många — null kan lagras under flera poster"
            },
            {
              "icon": "",
              "label": "Det beror på implementationen"
            }
          ]
        },
        {
          "question": "Du itererar en List med en for-each-slinga och anropar list.remove() på samma lista under iterationen. Vad händer?",
          "options": [
            {
              "icon": "",
              "label": "Det fungerar fint — List.remove() uppdaterar iteratorn"
            },
            {
              "icon": "",
              "label": "Det kastar en ConcurrentModificationException — du ändrar listan medan en iterator är aktiv"
            },
            {
              "icon": "",
              "label": "Det hoppar över det nästa elementet tyst"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel"
            }
          ]
        },
        {
          "question": "Vid körning, givet List<String> list, vad kan du faktiskt instansiera denna variabel med?",
          "options": [
            {
              "icon": "",
              "label": "Bara ArrayList<String>"
            },
            {
              "icon": "",
              "label": "En ArrayList, LinkedList, eller någon List-implementering — generiska typ-information tas bort vid körning (type erasure)"
            },
            {
              "icon": "",
              "label": "En ArrayList<String> eller LinkedList<String>, men inte en ArrayList<Object>"
            },
            {
              "icon": "",
              "label": "Bara en List som implementerar Serializable"
            }
          ]
        },
        {
          "question": "switch (day) { case 1: case 2: print(\"Weekday\"); break; case 6: print(\"Saturday\"); case 7: print(\"Sunday\"); break; default: print(\"?\"); } Om day är 6, vad skrivs ut?",
          "options": [
            {
              "icon": "",
              "label": "Bara \"Saturday\" — varje case-block i en switch stannar alltid efter sin egen print-sats"
            },
            {
              "icon": "",
              "label": "Bara \"Sunday\" — matchningen börjar vid case 6, men bara den sista matchande etiketten innan break körs"
            },
            {
              "icon": "",
              "label": "Inget skrivs ut, eftersom day 6 saknar ett matchande case med en egen break direkt under sig"
            },
            {
              "icon": "",
              "label": "\"Saturday\" och sedan \"Sunday\" — case 6 saknar break, så körningen faller igenom till nästa case:s kod innan den når följande break"
            }
          ]
        },
        {
          "question": "En Product-klass behöver en enda, uppenbar \"naturlig\" sorteringsordning. Vilken gränssnitt implementerar du?",
          "options": [
            {
              "icon": "",
              "label": "Comparable<Product> — implementera compareTo() för att definiera den naturliga ordningen"
            },
            {
              "icon": "",
              "label": "Comparator<Product> — använd istället denna för externa sorterare"
            },
            {
              "icon": "",
              "label": "Serializable"
            },
            {
              "icon": "",
              "label": "Cloneable"
            }
          ]
        },
        {
          "question": "En metod kallar new FileReader(path), som deklarerar throws IOException. Du måste hantera eller deklarera detta undantag. Vilken är den snälla vägen?",
          "options": [
            {
              "icon": "",
              "label": "try-with-resources: try (FileReader fr = new FileReader(path)) { ... } — den stänger automatiskt även om ett undantag inträffar"
            },
            {
              "icon": "",
              "label": "try-finally: try { FileReader fr = new FileReader(path); ... } finally { fr.close(); } — kräver manuell stängning"
            },
            {
              "icon": "",
              "label": "Båda fungerar lika bra"
            },
            {
              "icon": "",
              "label": "try-catch-finally är alltid obligatorisk"
            }
          ]
        },
        {
          "question": "try (Resource a = new Resource(\"A\"); Resource b = new Resource(\"B\")) { ... } använder två resurser som implementerar AutoCloseable. Om try-blocket avslutas normalt, i vilken ordning stängs de?",
          "options": [
            {
              "icon": "",
              "label": "A stängs först, sedan B, motsvarande deklarationsordning"
            },
            {
              "icon": "",
              "label": "B stängs först, sedan A — try-with-resources stänger resurser i omvänd ordning av hur de deklarerades"
            },
            {
              "icon": "",
              "label": "Båda stängs samtidigt, eftersom try-with-resources parallelliserar rengöring"
            },
            {
              "icon": "",
              "label": "Bara B stängs automatiskt — A måste fortfarande stängas manuellt i en finally-block"
            }
          ]
        },
        {
          "question": "int getValue() { try { return 1; } finally { return 2; } } Vad returnerar denna metod?",
          "options": [
            {
              "icon": "",
              "label": "1 — try-blockets returvärde är redan fastställt innan finally körs, så finally kan inte ändra det"
            },
            {
              "icon": "",
              "label": "Ett undantag kastas vid körning, eftersom en metod inte kan returnera från två ställen"
            },
            {
              "icon": "",
              "label": "2 — en return-sats i finally åsidosätter och ersätter en påbörjad return från try-blocket, vilket kastar bort värdet 1 helt"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel — finally får inte innehålla en return-sats"
            }
          ]
        },
        {
          "question": "try { ... } catch (IOException e) { ... } catch (FileNotFoundException e) { ... } — varför kan detta bli ett problem?",
          "options": [
            {
              "icon": "",
              "label": "Inget — båda är giltiga undantag"
            },
            {
              "icon": "",
              "label": "FileNotFoundException är en subtyp av IOException, så den andra catch kommer aldrig att köras; mer specifika undantag måste komma först"
            },
            {
              "icon": "",
              "label": "Du kan inte ha två catch-block"
            },
            {
              "icon": "",
              "label": "Du måste använda multi-catch: catch (IOException | FileNotFoundException e)"
            }
          ]
        },
        {
          "question": "En klass har en synchronized-instansmetod process() och en static synchronized-metod getStatus(). Kan de köras samtidigt?",
          "options": [
            {
              "icon": "",
              "label": "Nej — synchronized låser alltid samma globala mutex"
            },
            {
              "icon": "",
              "label": "Ja — en synchronized-instansmetod låser this-objektet, en static-metod låser Class-objektet, så de är två olika lås och kan köras samtidigt"
            },
            {
              "icon": "",
              "label": "Nej — static-metoder kan inte användas med synchronized"
            },
            {
              "icon": "",
              "label": "Det beror på JVM-implementationen"
            }
          ]
        },
        {
          "question": "Ett fält deklareras volatile int counter = 0;, och flera trådar inkrementerar det: counter++. Är detta trådsäkert?",
          "options": [
            {
              "icon": "",
              "label": "Ja — volatile garanterar atomicitet för alla operationer"
            },
            {
              "icon": "",
              "label": "Nej — volatile garanterar synlighet men inte atomicitet; counter++ är två operationer (läs, ändra, skriv) som kan interfolieras mellan trådar"
            },
            {
              "icon": "",
              "label": "Ja, men bara på en single-core-processor"
            },
            {
              "icon": "",
              "label": "Du behöver AtomicInteger istället"
            }
          ]
        },
        {
          "question": "Interface A och interface B deklarerar var sin default-metod def(). Class C implementerar båda: class C implements A, B { }. Vad händer?",
          "options": [
            {
              "icon": "",
              "label": "C ärver default-metoden från A"
            },
            {
              "icon": "",
              "label": "Det är ett kompileringsfel — diamantkonflikt; du måste åsidosätta def() i C för att välja vilken (eller ge en egen implementering)"
            },
            {
              "icon": "",
              "label": "Båda körs"
            },
            {
              "icon": "",
              "label": "B åsidosätter A automatiskt"
            }
          ]
        },
        {
          "question": "list.stream().filter(x -> x > 0).map(x -> x * 2); är skriven men aldrig anroppad (ingen terminal-operation). Vad händer?",
          "options": [
            {
              "icon": "",
              "label": "Elementen filtreras och mappas omedelbar"
            },
            {
              "icon": "",
              "label": "Ingenting — filter() och map() är mellanliggande operationer; Streams är lazy och körs inte förrän en terminal-operation dyker upp (.collect(), .forEach(), .toArray(), osv)"
            },
            {
              "icon": "",
              "label": "Ett kompileringsfel"
            },
            {
              "icon": "",
              "label": "NullPointerException"
            }
          ]
        }
      ],
      "optionOrderVersion": "0154f9576054ad6f"
    }
  }
}
