{
  "assessmentTests": {
    "java_test": {
      "name": "Bài Kiểm Tra Java",
      "desc": "30 câu hỏi tình huống về cú pháp cốt lõi, cơ học OOP, collections, generics, exceptions và concurrency — tìm hiểu liệu kỹ năng Java của bạn có phù hợp với ý nghĩa của thông báo tuyển dụng hay không.",
      "recommendation": "Hồ sơ kỹ năng Java của bạn",
      "results": {
        "beginner": {
          "name": "Người Mới Bắt Đầu",
          "desc": "Bạn có thể viết các lớp và phương thức hoạt động, nhưng những câu hỏi bạn sai tập trung xung quanh nhận dạng và giá trị mặc định hơn là cú pháp — String == so với .equals, tại sao new String(\"x\") không bao giờ tái sử dụng string pool, một trường số mặc định thành cái gì so với một trường wrapper. Không phải là do kỹ năng Java yếu; đây là những quy tắc cụ thể khiến những người học Java bằng trial and error chứ không phải từ cách references và primitives thực sự hoạt động bên dưới. Chúng quan trọng ở nơi làm việc vì mỗi quy tắc là nơi code biên dịch, chạy, và yên tĩnh làm điều sai.",
          "recommendation": "Hãy bắt đầu với ba điều, theo thứ tự này: tại sao == trên hai String objects so sánh references chứ không phải characters (và .equals là những gì bạn hầu như luôn muốn), làm thế nào int overflow bao quanh yên tĩnh thay vì ném, và tại sao một trường Integer không được khởi tạo mặc định thành null trong khi một int field mặc định thành 0. Hướng dẫn chính thức Java của Oracle và Baeldung đều bao gồm cả ba với ví dụ có thể chạy được."
        },
        "intermediate": {
          "name": "Trung Cấp",
          "desc": "Bạn xử lý mã ứng dụng hàng ngày một cách thoải mái — classes, collections, control flow thẳng — và sẽ không bị chậm bởi công việc tính năng thường xuyên. Khoảng cách giữa đây và Nâng Cao chủ yếu là những gì xảy ra khi các quy tắc Java tương tác với concurrency và generics: một static method được giải quyết bởi declared type thay vì object bạn mong đợi, một HashMap iteration order bạn yên tĩnh dựa vào, một ConcurrentModificationException từ việc loại bỏ một mục mid-loop. Đó là loại lỗi mà một kiểm tra nhanh qua mắt bỏ qua và chỉ xuất hiện dưới một điều kiện runtime cụ thể.",
          "recommendation": "Tập trung vào cách cách compiler's static view của code của bạn khác với những gì chạy: overload resolution và static-method hiding bởi declared type hơn là runtime type, tại sao HashMap không đưa ra bất kỳ lợi nhuận-thứ tự nào, và tại sao sửa đổi một list trực tiếp trong khi lặp ném ConcurrentModificationException. Sau đó là generics erasure, vì điều đó vấp phải những người đã biết collections riêng lẻ."
        },
        "advanced": {
          "name": "Nâng Cao",
          "desc": "Đây là cấp độ hầu hết thông báo tuyển dụng có nghĩa là \"Java mạnh.\" Bạn đọc một class có static blocks, instance blocks và nhiều constructors và có thể dự đoán thứ tự chính xác chúng chạy, bạn biết tại sao một finally block có thể yên tĩnh loại bỏ giá trị trả về của try block, và bạn sử dụng try-with-resources thay vì một finally-close thủ công vì bạn biết bảo đảm thứ tự nó cung cấp. Điều tách rời band này từ đỉnh cao là phía concurrent và interface-level của công việc: những gì synchronized thực sự khóa, những gì volatile làm và không bảo đảm, và cách default-method conflicts được giải quyết.",
          "recommendation": "Đẩy vào những phần bảo vệ code mà các luồng khác và các giao diện khác cũng chạm: sự khác biệt giữa những gì synchronized instance method khóa so với synchronized static method, tại sao volatile cung cấp visibility nhưng không phải atomicity cho counter++, và cách Java buộc bạn phải giải quyết default-method diamond bằng tay. Tài liệu Baeldung's và Java Concurrency in Practice's về Java Memory Model là điểm dừng tự nhiên tiếp theo cho cả hai."
        },
        "expert": {
          "name": "Chuyên Gia",
          "desc": "Bạn ghi điểm ở mức cao nhất trong mọi phần — core syntax và types, OOP mechanics và scope, collections và generics, và exceptions, concurrency và idioms. Thực tế, điều đó có nghĩa là bạn có thể được giao một class của người lạ và giải thích tại sao một compile error, một runtime exception, hoặc một giá trị yên tĩnh sai xảy ra, không chỉ những gì cú pháp nói rằng nó sẽ làm, đó là kỹ năng khó hơn và có giá trị hơn. Ở cấp độ này ngôn ngữ chính nó hiếm khi là yếu tố hạn chế; giới hạn thường là concurrency design hoặc hình dạng của dữ liệu bên dưới nó.",
          "recommendation": "Những lợi nhuận bây giờ là trong thiết kế và chẩn đoán: đọc một thread dump trước khi giả định một hang là một deadlock, lựa chọn giữa synchronized, java.util.concurrent locks và atomics như một tradeoff hơn là một mặc định, và stream-pipeline design mà ở lại lazy on purpose hơn là by accident. Nếu bạn đang được kiểm tra cho một vai trò, mô tả một concurrency bug như một missed happens-before edge hoặc một ConcurrentModificationException bạn tìm thấy trong sản xuất hơn là đặt tên các tính năng Java — nó chứng minh suy luận, không chỉ là từ vựng."
        }
      },
      "questions": [
        {
          "question": "Bạn tạo hai String objects: String a = new String(\"cat\"); String b = new String(\"cat\"); Điều gì mà a == b đánh giá thành?",
          "options": [
            {
              "icon": "",
              "label": "true — String literals cùng characters luôn là cùng object"
            },
            {
              "icon": "",
              "label": "true — new String(...) tái sử dụng string pool, vì vậy text giống hệt nhau luôn chia sẻ một object"
            },
            {
              "icon": "",
              "label": "Một compile error — == không thể được sử dụng để so sánh String objects"
            },
            {
              "icon": "",
              "label": "false — new String(...) luôn cấp phát một object mới trên heap, vì vậy == so sánh hai references khác nhau ngay cả khi .equals(b) sẽ trả về true"
            }
          ]
        },
        {
          "question": "Integer x = 100; Integer y = 100; System.out.println(x == y); rồi Integer x2 = 200; Integer y2 = 200; System.out.println(x2 == y2); Hai dòng in ra cái gì?",
          "options": [
            {
              "icon": "",
              "label": "true rồi true — autoboxed Integer objects luôn được cached không phụ thuộc giá trị"
            },
            {
              "icon": "",
              "label": "false rồi false — == trên Integer objects luôn là reference comparison, vì vậy giá trị bằng nhau không bao giờ khớp"
            },
            {
              "icon": "",
              "label": "true rồi false, nhưng chỉ vì 200 overflow một byte — ranh giới cache không liên quan đến -128..127"
            },
            {
              "icon": "",
              "label": "true rồi false — autoboxed Integer values từ -128 đến 127 được cached và chia sẻ, vì vậy 100 tái sử dụng một object, nhưng 200 rơi ngoài cache và autobox thành hai objects tách biệt"
            }
          ]
        },
        {
          "question": "int max = Integer.MAX_VALUE; System.out.println(max + 1); Điều gì xảy ra?",
          "options": [
            {
              "icon": "",
              "label": "Nó ném một ArithmeticException cho integer overflow"
            },
            {
              "icon": "",
              "label": "Nó in Integer.MAX_VALUE lại, vì Java kẹp ở maximum của type"
            },
            {
              "icon": "",
              "label": "Nó in Integer.MIN_VALUE — int arithmetic yên tĩnh bao quanh trên overflow thay vì ném"
            },
            {
              "icon": "",
              "label": "Nó là một compile error — compiler phát hiện overflow trước"
            }
          ]
        },
        {
          "question": "System.out.println(0.1 + 0.2 == 0.3); Điều này in ra cái gì, và tại sao?",
          "options": [
            {
              "icon": "",
              "label": "false — 0.1, 0.2 và 0.3 không thể được đại diện chính xác trong binary floating point, vì vậy sum tương tác rounding error mà làm nó không bit-for-bit bằng 0.3"
            },
            {
              "icon": "",
              "label": "true — Java làm tròn double arithmetic đến representable decimal gần nhất trước khi so sánh"
            },
            {
              "icon": "",
              "label": "true — addition của hai doubles luôn chính xác cho giá trị có hai decimal digits"
            },
            {
              "icon": "",
              "label": "Nó ném một exception, vì == không được định nghĩa cho double trong Java"
            }
          ]
        },
        {
          "question": "Một class khai báo hai instance fields không có initializer: int count; và Integer total; Trước constructor chạy, giá trị mặc định của chúng là cái gì?",
          "options": [
            {
              "icon": "",
              "label": "Cả hai mặc định thành 0, vì Integer autoboxes tới int tại field initialization"
            },
            {
              "icon": "",
              "label": "count là 0 và total là 0, boxed tự động lần đầu nó được đọc"
            },
            {
              "icon": "",
              "label": "count là 0 và total là null — primitive numeric fields mặc định thành zero, nhưng một uninitialized wrapper reference field mặc định thành null như bất kỳ object reference khác"
            },
            {
              "icon": "",
              "label": "Cả hai mặc định thành null cho đến khi được gán rõ ràng, vì Java không có implicit numeric defaults"
            }
          ]
        },
        {
          "question": "Một loop chạy 1000 lần, mỗi lần làm result += \"x\"; trên một String result. Điều gì thực sự xảy ra bên dưới mỗi iteration?",
          "options": [
            {
              "icon": "",
              "label": "Character array bên trong của String đang tồn tại được mở rộng tại chỗ"
            },
            {
              "icon": "",
              "label": "Java tự động batch concatenations và chỉ cấp phát một String object cuối cùng"
            },
            {
              "icon": "",
              "label": "Nó biên dịch thành một StringBuilder.append() call duy nhất chia sẻ trong tất cả 1000 iterations, không có extra object cấp phát per iteration"
            },
            {
              "icon": "",
              "label": "Một brand new String object được tạo và result được gán lại để trỏ vào nó — String object trước đó được loại bỏ, vì String là immutable và += không thể sửa đổi nó tại chỗ"
            }
          ]
        },
        {
          "question": "final List<String> names = new ArrayList<>(); Cái nào trong số này là true?",
          "options": [
            {
              "icon": "",
              "label": "names.add(\"Ana\") biên dịch và hoạt động tốt — final chỉ ngăn gán lại names reference chính nó, không phải mutating object nó trỏ tới"
            },
            {
              "icon": "",
              "label": "names.add(\"Ana\") là một compile error, vì final làm list chính nó unmodifiable"
            },
            {
              "icon": "",
              "label": "List là thread-safe cho concurrent writes vì nó được khai báo final"
            },
            {
              "icon": "",
              "label": "final trên một local variable không có hiệu lực trừ khi type cũng được khai báo immutable"
            }
          ]
        },
        {
          "question": "int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; System.out.println(a == b); System.out.println(Arrays.equals(a, b)); Hai dòng in ra cái gì?",
          "options": [
            {
              "icon": "",
              "label": "false rồi true — == so sánh array references (hai array objects khác nhau), trong khi Arrays.equals so sánh các elements"
            },
            {
              "icon": "",
              "label": "true rồi true — arrays cùng contents là cùng object trong Java"
            },
            {
              "icon": "",
              "label": "false rồi false — Arrays.equals chỉ hoạt động cho object arrays, không phải primitive int arrays"
            },
            {
              "icon": "",
              "label": "true rồi false — == trên arrays so sánh contents, và Arrays.equals là dư thừa"
            }
          ]
        },
        {
          "question": "void show(Object o) { print(\"Object\"); } void show(String s) { print(\"String\"); } Object ref = \"hello\"; show(ref); Cái nào overload chạy, và tại sao?",
          "options": [
            {
              "icon": "",
              "label": "show(String) chạy, vì Java kiểm tra actual runtime class của object trước khi chọn overload"
            },
            {
              "icon": "",
              "label": "show(Object) chạy — overload resolution được quyết định tại compile time bằng cách dùng declared type của variable, không phải actual runtime type của object nó tham chiếu"
            },
            {
              "icon": "",
              "label": "Nó là một compile error — Object không thể được truyền nơi một more specific overload tồn tại"
            },
            {
              "icon": "",
              "label": "Cả hai phương thức chạy, một lần mỗi cái, vì Java giải quyết overloads bằng cách thử mọi match"
            }
          ]
        },
        {
          "question": "Class Base có static void greet() { print(\"Base\"); }. Class Derived extends Base và cũng khai báo static void greet() { print(\"Derived\"); }. Bạn viết: Base ref = new Derived(); ref.greet(); Cái gì in ra?",
          "options": [
            {
              "icon": "",
              "label": "Derived — static methods override giống như instance methods, theo dõi actual object's runtime type"
            },
            {
              "icon": "",
              "label": "Nó là một compile error — static methods không thể được gọi thông qua một instance reference"
            },
            {
              "icon": "",
              "label": "Base — static methods không phải polymorphic; gọi một thông qua một reference được giải quyết bởi reference's declared type tại compile time, không phải object's actual type"
            },
            {
              "icon": "",
              "label": "Cả Base và Derived in, vì call giải quyết thành cả hidden và hiding versions"
            }
          ]
        },
        {
          "question": "Bên trong một method, bạn viết int count = 0; rồi cố gắng tham chiếu count từ bên trong một lambda được truyền tới method khác. Cái gì phải là true về count để điều này biên dịch?",
          "options": [
            {
              "icon": "",
              "label": "count phải là effectively final — không bao giờ được gán lại bất cứ nơi nào sau giá trị ban đầu của nó — vì một lambda captures một snapshot, không phải một live reference tới một mutable local variable"
            },
            {
              "icon": "",
              "label": "Không có gì — bất kỳ local variable nào có thể được tự do đọc và gán lại từ bên trong một lambda"
            },
            {
              "icon": "",
              "label": "count phải được khai báo volatile vì lambda luôn thấy giá trị mới nhất của nó"
            },
            {
              "icon": "",
              "label": "count phải là một field, không phải một local variable — lambdas không thể capture locals"
            }
          ]
        },
        {
          "question": "void rename(StringBuilder sb) { sb = new StringBuilder(\"new\"); } được gọi là StringBuilder original = new StringBuilder(\"old\"); rename(original); Cái gì là original sau call?",
          "options": [
            {
              "icon": "",
              "label": "Trở thành \"new\" — objects được truyền by reference trong Java, vì vậy gán lại parameter thay đổi caller's variable quá"
            },
            {
              "icon": "",
              "label": "Trở thành \"new\" chỉ cho mutable types như StringBuilder, nhưng không phải cho immutable types"
            },
            {
              "icon": "",
              "label": "Vẫn \"old\" — Java truyền reference chính nó by value, vì vậy gán lại parameter bên trong method chỉ repoints local copy của reference, rời caller's original chưa được chạm"
            },
            {
              "icon": "",
              "label": "Ném một runtime exception, vì sb được gán lại bên trong method"
            }
          ]
        },
        {
          "question": "Một class có một static initializer block, một instance initializer block, và một constructor, theo thứ tự source đó. Bạn tạo hai objects của class này một sau một. Những thứ này chạy theo thứ tự nào?",
          "options": [
            {
              "icon": "",
              "label": "Static block chạy chính xác một lần, lần đầu tiên class được tải; rồi cho mỗi object, instance block chạy rồi constructor body chạy"
            },
            {
              "icon": "",
              "label": "Tất cả ba chạy fresh, theo thứ tự source, cho mỗi single object được tạo"
            },
            {
              "icon": "",
              "label": "Constructor chạy đầu tiên cho mỗi object, rồi instance block, rồi static block một lần ở rất cuối"
            },
            {
              "icon": "",
              "label": "Static block chạy một lần per object, ngay trước instance block"
            }
          ]
        },
        {
          "question": "Một class có void log(String s) và void log(String... args). Bạn gọi log(\"hi\"). Cái nào chạy?",
          "options": [
            {
              "icon": "",
              "label": "log(String... args) — varargs overloads luôn được ưu tiên khi cả hai áp dụng"
            },
            {
              "icon": "",
              "label": "Nó là một compile error — call là ambiguous giữa hai overloads"
            },
            {
              "icon": "",
              "label": "log(String s) — khi một fixed-arity overload khớp chính xác, Java luôn ưu tiên nó trên một varargs overload, cái chỉ được sử dụng như một last resort"
            },
            {
              "icon": "",
              "label": "Cái nào được khai báo đầu tiên trong source file chạy"
            }
          ]
        },
        {
          "question": "Dòng đầu tiên của một constructor gọi this(0); để delegate tới constructor khác trong cùng class. Nơi nào được phép điều này xuất hiện?",
          "options": [
            {
              "icon": "",
              "label": "Bất cứ nơi nào trong constructor body, miễn là nó chạy trước object được trả về"
            },
            {
              "icon": "",
              "label": "Chỉ như dòng đầu tiên rất của constructor — this() (hoặc super()) phải là dòng đầu tiên, và một constructor không thể gọi cả this() và super()"
            },
            {
              "icon": "",
              "label": "Chỉ như dòng cuối cùng, sau khi tất cả field initialization hoàn thành"
            },
            {
              "icon": "",
              "label": "Chỉ trong constructors đánh dấu rõ ràng như delegating, dùng một delegate keyword"
            }
          ]
        },
        {
          "question": "Bạn cần một list mà sẽ có elements chèn ở front cực kỳ thường xuyên, và random-access reads hiếm. Cái nào là better structural fit, và tại sao?",
          "options": [
            {
              "icon": "",
              "label": "ArrayList — backing array contiguous của nó làm mỗi operation, bao gồm front-insertion, nhanh hơn một linked structure"
            },
            {
              "icon": "",
              "label": "Chúng thực hiện giống hệt nhau, vì cả hai implement List interface cùng time guarantees"
            },
            {
              "icon": "",
              "label": "LinkedList — chèn ở front là O(1) vì nó chỉ relinks một node, trong khi ArrayList phải shift mọi element tồn tại lên một, làm front-insertion O(n)"
            },
            {
              "icon": "",
              "label": "LinkedList, vì nó hỗ trợ random access trong O(1) trong khi ArrayList không"
            }
          ]
        },
        {
          "question": "Bạn chèn năm entries vào một plain HashMap theo một thứ tự cụ thể, rồi iterate over nó cùng một for-each loop. Thứ tự nào mà entries xuất hiện?",
          "options": [
            {
              "icon": "",
              "label": "Cùng thứ tự mà entries được chèn, vì Java maps luôn bảo tồn insertion order"
            },
            {
              "icon": "",
              "label": "Không có thứ tự được bảo đảm ở tất cả — HashMap's iteration order phụ thuộc vào hash bucket placement, không phải insertion order, và có thể thay đổi giữa runs; LinkedHashMap là gì bảo tồn insertion order"
            },
            {
              "icon": "",
              "label": "Được sắp xếp bởi key tự động, cùng cách một TreeMap hoạt động"
            },
            {
              "icon": "",
              "label": "Reverse của insertion order, vì HashMap nội bộ sử dụng một stack"
            }
          ]
        },
        {
          "question": "Có bao nhiêu null keys có thể một plain java.util.HashMap giữ tại một lần, và bao nhiêu null values?",
          "options": [
            {
              "icon": "",
              "label": "Không null keys và không null values bao giờ được cho phép trong bất kỳ Map implementation nào"
            },
            {
              "icon": "",
              "label": "Một null key tại hầu hết, và bất kỳ số lượng null values — HashMap cho phép một single null key, không giống Hashtable cái cho phép cả hai"
            },
            {
              "icon": "",
              "label": "Unlimited null keys và unlimited null values, vì null được coi như bất kỳ key khác"
            },
            {
              "icon": "",
              "label": "Một null key và một null value maximum, cả hai capped tại một"
            }
          ]
        },
        {
          "question": "Bạn iterate một List cùng một for-each loop và gọi list.remove(item) trực tiếp trên list từ bên trong loop body, trên một số nhưng không phải tất cả elements. Điều gì xảy ra?",
          "options": [
            {
              "icon": "",
              "label": "Nó hoạt động chính xác và loại bỏ chính xác các elements dự định"
            },
            {
              "icon": "",
              "label": "Nó yên tĩnh bỏ qua element sau cái được loại bỏ, nhưng cách khác hoàn thành không có error"
            },
            {
              "icon": "",
              "label": "Nó ném IndexOutOfBoundsException một khi loop đạt old size của list"
            },
            {
              "icon": "",
              "label": "Nó ném ConcurrentModificationException — sửa đổi list's structure trực tiếp trong khi một implicit iterator đang đi bộ qua nó được phát hiện và từ chối; Iterator.remove() phải được sử dụng thay vào đó"
            }
          ]
        },
        {
          "question": "Tại runtime, được cấp một List<String> list, cái gì bạn thực sự có thể xác định về generic type parameter của nó thông qua reflection hoặc instanceof?",
          "options": [
            {
              "icon": "",
              "label": "Bạn có thể gọi list.getElementType() để retrieve String.class tại runtime"
            },
            {
              "icon": "",
              "label": "instanceof List<String> biên dịch và chính xác kiểm tra element type"
            },
            {
              "icon": "",
              "label": "JVM lưu trữ type parameter như hidden metadata có thể truy cập thông qua list.getGenericType()"
            },
            {
              "icon": "",
              "label": "Không gì — generic type information được xóa tại compile time, vì vậy tại runtime object chỉ là một List, và không có cách nào để khôi phục liệu nó được khai báo List<String> hoặc List<Integer>"
            }
          ]
        },
        {
          "question": "switch (day) { case 1: case 2: print(\"Weekday\"); break; case 6: print(\"Saturday\"); case 7: print(\"Sunday\"); break; default: print(\"?\"); } Nếu day là 6, cái gì in ra?",
          "options": [
            {
              "icon": "",
              "label": "Chỉ Saturday — mỗi case block trong một switch luôn dừng sau print statement của nó"
            },
            {
              "icon": "",
              "label": "Chỉ Sunday — matching bắt đầu tại case 6 nhưng chỉ matching label cuối cùng trước break thực thi"
            },
            {
              "icon": "",
              "label": "Không có gì in, vì day 6 không có matching case cùng break trực tiếp dưới nó"
            },
            {
              "icon": "",
              "label": "Saturday rồi Sunday — case 6 không có break, vì vậy execution rơi qua vào code case tiếp theo trước khi hit break theo sau"
            }
          ]
        },
        {
          "question": "Một Product class cần một single, obvious \"natural\" sort order bởi price, cộng với khả năng để cũng sắp xếp bởi name hoặc bởi stock level tại different places trong codebase. Cái nào combination là right design?",
          "options": [
            {
              "icon": "",
              "label": "Implement Comparable<Product> ba lần riêng biệt, một per ordering, và cho phép caller chọn cái nào compareTo chạy"
            },
            {
              "icon": "",
              "label": "Implement Comparable<Product> cho natural price ordering, và viết separate Comparator<Product> instances cho name và stock-level orderings dùng ở nơi khác"
            },
            {
              "icon": "",
              "label": "Dùng chỉ Comparator cho mỗi ordering, bao gồm price, vì Comparable không có lợi thế ở đây"
            },
            {
              "icon": "",
              "label": "Dùng chỉ Comparable bằng cách thêm ba overloaded compareTo methods, một per ordering"
            }
          ]
        },
        {
          "question": "Một method gọi new FileReader(path), cái khai báo throws IOException. IOException extends Exception, không phải RuntimeException. Cái gì bạn phải làm để làm điều này biên dịch?",
          "options": [
            {
              "icon": "",
              "label": "Không gì — compiler chỉ thực thi cái này cho exceptions mà extend RuntimeException"
            },
            {
              "icon": "",
              "label": "Hoặc catch IOException trong một try/catch hoặc khai báo throws IOException trên method của bạn — checked exceptions phải được xử lý hoặc truyền rõ ràng, không giống unchecked RuntimeException subclasses"
            },
            {
              "icon": "",
              "label": "Wrap call trong một try/catch cho RuntimeException, vì IOException tự động được unchecked trong modern Java"
            },
            {
              "icon": "",
              "label": "Khai báo method như static — static methods được exempt từ checked exception handling"
            }
          ]
        },
        {
          "question": "try (Resource a = new Resource(\"A\"); Resource b = new Resource(\"B\")) { ... } dùng hai resources implementing AutoCloseable. Nếu try block hoàn thành bình thường, theo thứ tự nào chúng được closed?",
          "options": [
            {
              "icon": "",
              "label": "A được closed đầu tiên, rồi B, khớp declaration order"
            },
            {
              "icon": "",
              "label": "B được closed đầu tiên, rồi A — try-with-resources closes resources theo reverse của thứ tự chúng được khai báo"
            },
            {
              "icon": "",
              "label": "Cả hai được closed đồng thời, vì try-with-resources parallelizes cleanup"
            },
            {
              "icon": "",
              "label": "Chỉ B được closed tự động — A vẫn phải được closed thủ công trong một finally block"
            }
          ]
        },
        {
          "question": "int getValue() { try { return 1; } finally { return 2; } } Cái gì mà gọi getValue() trả về?",
          "options": [
            {
              "icon": "",
              "label": "1 — return value của try block đã được committed trước finally chạy, vì vậy finally không thể thay đổi nó"
            },
            {
              "icon": "",
              "label": "Nó ném một exception tại runtime, vì một method không thể trả về từ hai places"
            },
            {
              "icon": "",
              "label": "2 — một return statement bên trong finally overrides và thay thế bất kỳ return đã trong progress từ try block, loại bỏ giá trị 1 hoàn toàn"
            },
            {
              "icon": "",
              "label": "Nó là một compile error — finally không được phép chứa một return statement"
            }
          ]
        },
        {
          "question": "try { ... } catch (IOException e) { ... } catch (FileNotFoundException e) { ... }, và FileNotFoundException extends IOException. Cái gì xảy ra khi bạn cố gắng biên dịch cái này?",
          "options": [
            {
              "icon": "",
              "label": "Một compile error — FileNotFoundException catch block là unreachable vì earlier, more general IOException catch block đã khớp mọi FileNotFoundException"
            },
            {
              "icon": "",
              "label": "Nó biên dịch tốt, và more specific FileNotFoundException block chạy bất cứ khi nào loại chính xác đó được ném"
            },
            {
              "icon": "",
              "label": "Nó biên dịch tốt, và cả hai catch blocks chạy theo thứ tự cho một FileNotFoundException"
            },
            {
              "icon": "",
              "label": "Nó tốt tại compile time nhưng ném một runtime error lần đầu tiên một FileNotFoundException thực sự xảy ra"
            }
          ]
        },
        {
          "question": "Một class có một synchronized instance method process() và một synchronized static method configure(). Cái gì, cụ thể, mà mỗi khóa?",
          "options": [
            {
              "icon": "",
              "label": "process() khóa monitor của object instance cụ thể nó được gọi trên, trong khi configure() khóa monitor của Class object chính nó — chia sẻ bởi mỗi instance"
            },
            {
              "icon": "",
              "label": "Cả hai khóa cùng single global lock cho toàn bộ JVM, không phụ thuộc instance hoặc class"
            },
            {
              "icon": "",
              "label": "process() khóa Class object, và configure() khóa cái nào instance xảy ra gọi nó"
            },
            {
              "icon": "",
              "label": "Cả hai không thực sự khóa bất kỳ gì trừ khi một synchronized block cũng được sử dụng bên trong method body"
            }
          ]
        },
        {
          "question": "Một field được khai báo volatile int counter = 0;, và multiple threads chạy counter++ trên nó đồng thời. Làm volatile ngăn lost updates ở đây không?",
          "options": [
            {
              "icon": "",
              "label": "Có — volatile làm mỗi operation trên field atomic, bao gồm increments"
            },
            {
              "icon": "",
              "label": "Không — volatile chỉ bảo đảm rằng reads thấy latest write trên threads (visibility); counter++ là một read-modify-write cùng multiple steps, và volatile làm không có gì để làm những bước atomic"
            },
            {
              "icon": "",
              "label": "Có, nhưng chỉ cho int và long fields cụ thể, vì cách JVM xử lý 64-bit values"
            },
            {
              "icon": "",
              "label": "Không, và volatile cũng thất bại để bảo đảm visibility cho primitive types như int"
            }
          ]
        },
        {
          "question": "Interface A và interface B mỗi cái khai báo một default method describe(). Một class implements cả A và B và không override describe() chính nó. Cái gì xảy ra?",
          "options": [
            {
              "icon": "",
              "label": "Compiler chọn interface A's version tự động, vì nó được liệt kê đầu tiên trong implements clause"
            },
            {
              "icon": "",
              "label": "Cả hai versions chạy, một sau lần khác, bất cứ khi nào describe() được gọi"
            },
            {
              "icon": "",
              "label": "Nó tốt tại compile time, nhưng ném một AmbiguousMethodException lần đầu tiên describe() được gọi"
            },
            {
              "icon": "",
              "label": "Một compile error — khi hai interfaces đóng góp cùng default method, implementing class phải override nó chính nó để giải quyết ambiguity, vì Java sẽ không đoán cái nào bạn có ý"
            }
          ]
        },
        {
          "question": "list.stream().filter(x -> x > 0).map(x -> x * 2); được viết nhưng result không bao giờ được gán tới một terminal operation như .collect() hoặc .forEach(). Cái gì thực sự xảy ra khi dòng này thực thi?",
          "options": [
            {
              "icon": "",
              "label": "Không có gì xảy ra tới elements của list ở tất cả — filter và map là lazy intermediate operations mà chỉ tạo lên một pipeline description; không có một terminal operation, không có của pipeline đó bao giờ thực sự chạy"
            },
            {
              "icon": "",
              "label": "Mỗi element được filtered và mapped ngay lập tức, chính xác như nếu một terminal operation được gọi"
            },
            {
              "icon": "",
              "label": "Chỉ filter chạy ngay lập tức; map là deferred cho đến khi một terminal operation xuất hiện"
            },
            {
              "icon": "",
              "label": "Nó ném một IllegalStateException, vì một stream pipeline yêu cầu một terminal operation để biên dịch"
            }
          ]
        }
      ],
      "optionOrderVersion": "0154f9576054ad6f"
    }
  }
}
