{
  "assessmentTests": {
    "java_test": {
      "name": "Java 测试",
      "desc": "30 道关于核心语法、面向对象、集合、泛型、异常和并发的情景题 — 判断你对 Java 的理解是否与职位要求的 Java 工作能力相符。",
      "recommendation": "你的 Java 技能概览",
      "results": {
        "beginner": {
          "name": "初级",
          "desc": "你能写出工作的类和方法，但你错的题往往聚焦在恒等性和默认值而不是语法 — String 的 == 对比 .equals、为什么 new String(\"x\") 永远不会重用字符串池、数值字段默认值与包装字段默认值的区别。这都不是说你 Java 能力不行；这些是通过试错而不是从引用和原始值在底层如何运作来学 Java 的人容易踩坑的特定规则。在工作中很重要，因为每一个这样的坑都是代码编译、运行，却悄悄做错事的地方。",
          "recommendation": "先集中学三样东西，按这个顺序：为什么 == 在两个 String 对象上比较引用而非字符（而 .equals 几乎总是你想要的）、int 溢出如何悄悄换行而非抛异常、为什么未初始化的 Integer 字段默认值是 null，而 int 字段默认值是 0。Oracle 官方 Java 教程和 Baeldung 都用可运行的例子讲了这三个。"
        },
        "intermediate": {
          "name": "中级",
          "desc": "你日常应用代码写得很顺手 — 类、集合、直白的控制流 — 日常功能工作不会让你放慢速度。从这里到高级的差距主要在 Java 规则与并发和泛型互相作用时会发生什么：一个用声明类型而非期望对象的实际类型来解析的静态方法、一个你悄悄依赖的 HashMap 迭代顺序、一个从列表中间移除元素时抛出的 ConcurrentModificationException。这些是通过眼神检查能过的 bug，只有在特定运行时条件下才会显露。",
          "recommendation": "专注编译器对你代码的静态视图如何与运行时差异：过载解析和静态方法被声明类型而非运行时类型隐藏、为什么 HashMap 不保证迭代顺序、为什么在迭代时直接修改列表抛出 ConcurrentModificationException。然后学泛型擦除，因为这个绊倒已经分别知道集合框架的人。"
        },
        "advanced": {
          "name": "高级",
          "desc": "这是大多数职位招聘信息说的「懂 Java」的等级。你读一个类有静态块、实例块和多个构造器能预测它们的精确运行顺序，你知道为什么 finally 块能悄悄丢弃 try 块的返回值，你会选择 try-with-resources 而不是手工 finally-close，因为你知道它给你的顺序保证。把这个等级和顶级分开的是并发和接口等级工作的一侧：synchronized 实际锁什么、volatile 做和不做什么、默认方法冲突如何解决。",
          "recommendation": "深入那些保护其他线程和其他接口也要动的代码的部分：synchronized 实例方法锁什么 vs synchronized 静态方法锁什么、为什么 volatile 给可见性但不给 counter++ 的原子性、Java 如何强制你手工解决默认方法钻石问题。Baeldung 和《Java Concurrency in Practice》关于 Java Memory Model 的资料是这两者的下一步。"
        },
        "expert": {
          "name": "专家",
          "desc": "你在每一部分都拿了高分 — 核心语法和类型、面向对象和作用域、集合和泛型、异常、并发和习语。实际上这意味着你可以被扔进一个陌生人的类，解释为什么出现编译错误、运行时异常或悄悄错的值，而不只是语法说应该怎样，后者才是更难、更有价值的技能。在这个等级，语言本身很少是限制因子；限制通常来自并发设计或底层数据的形状。",
          "recommendation": "收益现在来自设计和诊断：读一个线程转储而不是假设死锁、在 synchronized、java.util.concurrent 锁和原子量之间选择作为权衡而不是默认、stream 管道设计故意保持惰性而不是意外。如果你在因一个职位而被筛选，讲一个像漏掉 happens-before 边界或生产环境中找到的 ConcurrentModificationException 这样的并发 bug，而不是数 Java 特性 — 这展示的是你的推理能力，而不只是词汇。"
        }
      },
      "questions": [
        {
          "question": "你创建两个 String 对象：String a = new String(\"cat\"); String b = new String(\"cat\"); a == b 计算为什么？",
          "options": [
            {
              "icon": "",
              "label": "true — 字符相同的 String 字面值总是同一个对象"
            },
            {
              "icon": "",
              "label": "true — new String(...) 重用字符串池，所以相同的文本总是共享一个对象"
            },
            {
              "icon": "",
              "label": "编译错误 — == 不能用来比较 String 对象"
            },
            {
              "icon": "",
              "label": "false — new String(...) 总是在堆上分配一个新对象，所以 == 比较两个不同引用，即使 .equals(b) 会返回 true"
            }
          ]
        },
        {
          "question": "Integer x = 100; Integer y = 100; System.out.println(x == y); 然后 Integer x2 = 200; Integer y2 = 200; System.out.println(x2 == y2); 这两行打印什么？",
          "options": [
            {
              "icon": "",
              "label": "true 然后 true — 自动装箱的 Integer 对象总是被缓存，不管值多大"
            },
            {
              "icon": "",
              "label": "false 然后 false — Integer 对象上 == 总是引用比较，所以相等的值永不匹配"
            },
            {
              "icon": "",
              "label": "true 然后 false，但只是因为 200 溢出了 byte — 缓存边界与 -128..127 无关"
            },
            {
              "icon": "",
              "label": "true 然后 false — 自动装箱的 Integer 值从 -128 到 127 被缓存和共享，所以 100 重用一个对象，但 200 超出缓存范围自动装箱成两个分别的对象"
            }
          ]
        },
        {
          "question": "int max = Integer.MAX_VALUE; System.out.println(max + 1); 会发生什么？",
          "options": [
            {
              "icon": "",
              "label": "它抛出一个 ArithmeticException 整数溢出异常"
            },
            {
              "icon": "",
              "label": "它再次打印 Integer.MAX_VALUE，因为 Java 在类型最大值处钳位"
            },
            {
              "icon": "",
              "label": "它打印 Integer.MIN_VALUE — int 运算在溢出时悄悄换行而非抛异常"
            },
            {
              "icon": "",
              "label": "这是编译错误 — 编译器提前检测溢出"
            }
          ]
        },
        {
          "question": "System.out.println(0.1 + 0.2 == 0.3); 这打印什么，为什么？",
          "options": [
            {
              "icon": "",
              "label": "false — 0.1、0.2 和 0.3 在二进制浮点中无法精确表示，所以和携带四舍五入误差，使其位对位不等于 0.3"
            },
            {
              "icon": "",
              "label": "true — Java 四舍五入双精度运算到最近的可表示十进制后再比较"
            },
            {
              "icon": "",
              "label": "true — 两个双精度的加法对两位小数值总是精确的"
            },
            {
              "icon": "",
              "label": "它抛一个异常，因为 == 对 double 无定义"
            }
          ]
        },
        {
          "question": "一个类声明两个实例字段无初始化器：int count; 和 Integer total; 构造器运行前，它们的默认值是什么？",
          "options": [
            {
              "icon": "",
              "label": "两个都默认为 0，因为 Integer 在字段初始化时自动装箱为 int"
            },
            {
              "icon": "",
              "label": "count 是 0，total 是 0，第一次读时自动装箱"
            },
            {
              "icon": "",
              "label": "count 是 0，total 是 null — 原始数值字段默认为零，但未初始化的包装引用字段像任何其他对象引用一样默认为 null"
            },
            {
              "icon": "",
              "label": "两个都默认为 null，直到显式赋值，因为 Java 没有隐含数值默认"
            }
          ]
        },
        {
          "question": "一个循环运行 1000 次，每次都在 String result 上执行 result += \"x\";。底层实际发生什么？",
          "options": [
            {
              "icon": "",
              "label": "现有 String 对象的内部字符数组就地扩展"
            },
            {
              "icon": "",
              "label": "Java 自动批处理拼接，只分配一个最终 String 对象"
            },
            {
              "icon": "",
              "label": "它编译成整个 1000 次迭代中共享的单个 StringBuilder.append() 调用，无迭代时额外对象分配"
            },
            {
              "icon": "",
              "label": "一个全新 String 对象被创建，result 被重指向它 — 前一个 String 对象被丢弃，因为 String 不可变，+= 不能原地修改它"
            }
          ]
        },
        {
          "question": "final List<String> names = new ArrayList<>(); 以下哪个为真？",
          "options": [
            {
              "icon": "",
              "label": "names.add(\"Ana\") 编译并工作正常 — final 只阻止重新赋值 names 引用本身，不阻止修改它指向的对象"
            },
            {
              "icon": "",
              "label": "names.add(\"Ana\") 是编译错误，因为 final 使列表本身不可修改"
            },
            {
              "icon": "",
              "label": "这个列表对并发写是线程安全的，因为它被声明为 final"
            },
            {
              "icon": "",
              "label": "final 在本地变量上无效，除非类型也被声明为不可变"
            }
          ]
        },
        {
          "question": "int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; System.out.println(a == b); System.out.println(Arrays.equals(a, b)); 这两行打印什么？",
          "options": [
            {
              "icon": "",
              "label": "false 然后 true — == 比较数组引用（两个不同数组对象），而 Arrays.equals 比较元素"
            },
            {
              "icon": "",
              "label": "true 然后 true — 内容相同的数组在 Java 中是同一个对象"
            },
            {
              "icon": "",
              "label": "false 然后 false — Arrays.equals 只对对象数组工作，不对原始 int 数组工作"
            },
            {
              "icon": "",
              "label": "true 然后 false — 数组上 == 比较内容，Arrays.equals 是冗余的"
            }
          ]
        },
        {
          "question": "void show(Object o) { print(\"Object\"); } void show(String s) { print(\"String\"); } Object ref = \"hello\"; show(ref); 哪个过载运行，为什么？",
          "options": [
            {
              "icon": "",
              "label": "show(String) 运行，因为 Java 在挑过载前检查对象的实际运行时类"
            },
            {
              "icon": "",
              "label": "show(Object) 运行 — 过载解析在编译时用变量的声明类型决定，不是对象的实际运行时类"
            },
            {
              "icon": "",
              "label": "编译错误 — Object 无法传给更具体的过载存在的地方"
            },
            {
              "icon": "",
              "label": "两个方法都运行，各一次，因为 Java 通过尝试每个匹配来解析过载"
            }
          ]
        },
        {
          "question": "类 Base 有 static void greet() { print(\"Base\"); }。类 Derived 继承 Base 并也声明 static void greet() { print(\"Derived\"); }。你写：Base ref = new Derived(); ref.greet(); 打印什么？",
          "options": [
            {
              "icon": "",
              "label": "Derived — 静态方法像实例方法一样覆盖，跟随实际对象的运行时类"
            },
            {
              "icon": "",
              "label": "编译错误 — 静态方法无法通过实例引用调用"
            },
            {
              "icon": "",
              "label": "Base — 静态方法不是多态的；通过引用调用一个在编译时被声明类型而非对象的实际类型解析"
            },
            {
              "icon": "",
              "label": "Base 和 Derived 都打印，因为调用解析成隐藏和隐藏两个版本"
            }
          ]
        },
        {
          "question": "在方法内，你写 int count = 0; 然后尝试从传递给另一方法的 lambda 内引用 count。为了编译，count 必须满足什么？",
          "options": [
            {
              "icon": "",
              "label": "count 必须是有效最终值 — 初始值后永不重新赋值 — 因为 lambda 捕获快照，不是活引用到可变本地变量"
            },
            {
              "icon": "",
              "label": "什么都不需要 — 任何本地变量都能自由读取和重新赋值在 lambda 内"
            },
            {
              "icon": "",
              "label": "count 必须声明为 volatile 所以 lambda 总是看到最新值"
            },
            {
              "icon": "",
              "label": "count 必须是字段，不是本地变量 — lambda 根本无法捕获本地"
            }
          ]
        },
        {
          "question": "void rename(StringBuilder sb) { sb = new StringBuilder(\"new\"); } 被调用为 StringBuilder original = new StringBuilder(\"old\"); rename(original); original 调用后是什么？",
          "options": [
            {
              "icon": "",
              "label": "变成「new」— 对象在 Java 中按引用传递，所以重新赋值参数改变调用方的变量"
            },
            {
              "icon": "",
              "label": "变成「new」只对 StringBuilder 这样的可变类型，但不对不可变类型"
            },
            {
              "icon": "",
              "label": "仍为「old」— Java 按值传递引用本身，所以重新赋值方法内参数只重指向本地引用副本，留下调用方的原始不动"
            },
            {
              "icon": "",
              "label": "抛运行时异常，因为 sb 在方法内被重新赋值"
            }
          ]
        },
        {
          "question": "一个类有一个静态初始化块、一个实例初始化块和一个构造器，源顺序如此。你一个接一个创建这个类的两个对象。这些以什么顺序运行？",
          "options": [
            {
              "icon": "",
              "label": "静态块恰好运行一次，第一次类被加载时；然后对每个对象，实例块运行然后构造器体运行"
            },
            {
              "icon": "",
              "label": "全部三个对每个对象运行新鲜，按源顺序"
            },
            {
              "icon": "",
              "label": "构造器对每个对象先运行，然后实例块，然后最后静态块一次"
            },
            {
              "icon": "",
              "label": "静态块对每个对象运行一次，恰好在实例块前"
            }
          ]
        },
        {
          "question": "一个类有 void log(String s) 和 void log(String... args)。你调用 log(\"hi\")。哪个运行？",
          "options": [
            {
              "icon": "",
              "label": "log(String... args) — 当两者都适用时，变参过载总是首选"
            },
            {
              "icon": "",
              "label": "编译错误 — 调用在两个过载间是模糊的"
            },
            {
              "icon": "",
              "label": "log(String s) — 当固定数目过载完全匹配时，Java 总是选它而非变参过载，只在最后出路使用变参"
            },
            {
              "icon": "",
              "label": "源文件中哪个先声明的就运行哪个"
            }
          ]
        },
        {
          "question": "构造器的第一行调用 this(0); 委托给同一类中的另一个构造器。this() 允许出现在哪里？",
          "options": [
            {
              "icon": "",
              "label": "构造器体中任何地方，只要它在对象被返回前运行"
            },
            {
              "icon": "",
              "label": "只作为构造器的最首行 — this()（或 super()）必须是第一行，构造器不能同时调用 this() 和 super()"
            },
            {
              "icon": "",
              "label": "只作最后语句，在所有字段初始化完成后"
            },
            {
              "icon": "",
              "label": "只在用委托关键字显式标记的构造器中"
            }
          ]
        },
        {
          "question": "你需要一个会在前端经常插入元素的列表，而随机读取很少。哪个是更好的结构拟合，为什么？",
          "options": [
            {
              "icon": "",
              "label": "ArrayList — 它的连续备份数组使包括前端插入在内的每个操作都比链接结构快"
            },
            {
              "icon": "",
              "label": "它们执行相同，因为两个都实现 List 接口且有相同的时间保证"
            },
            {
              "icon": "",
              "label": "LinkedList — 前端插入是 O(1) 因为它只是重新链接一个节点，而 ArrayList 必须把每个现有元素上移一个，使前端插入 O(n)"
            },
            {
              "icon": "",
              "label": "LinkedList，因为它支持 O(1) 随机读取而 ArrayList 不"
            }
          ]
        },
        {
          "question": "你按特定顺序向一个普通 HashMap 插入五个条目，然后用 for-each 循环迭代它。条目以什么顺序出现？",
          "options": [
            {
              "icon": "",
              "label": "条目被插入的相同顺序，因为 Java 映射总是保持插入顺序"
            },
            {
              "icon": "",
              "label": "无保证顺序 — HashMap 迭代顺序依赖哈希桶位置，不是插入顺序，甚至在不同运行间能改变；LinkedHashMap 是保持插入顺序的"
            },
            {
              "icon": "",
              "label": "按键自动排序，就像 TreeMap 那样"
            },
            {
              "icon": "",
              "label": "插入顺序的反向，因为 HashMap 内部使用栈"
            }
          ]
        },
        {
          "question": "一个普通 java.util.HashMap 一次最多能持有多少个 null 键，多少个 null 值？",
          "options": [
            {
              "icon": "",
              "label": "无 null 键且无 null 值在任何 Map 实现中被允许"
            },
            {
              "icon": "",
              "label": "最多一个 null 键，任意数量的 null 值 — HashMap 允许单个 null 键，不像 Hashtable 都不允许"
            },
            {
              "icon": "",
              "label": "无限 null 键和无限 null 值，因为 null 被当作任何其他键对待"
            },
            {
              "icon": "",
              "label": "最多一个 null 键和一个 null 值，两个都被上限"
            }
          ]
        },
        {
          "question": "你用 for-each 循环迭代一个 List，在循环体内直接对列表调用 list.remove(item)，在某些但非全部元素上。会发生什么？",
          "options": [
            {
              "icon": "",
              "label": "它正确工作并移除恰好预期的元素"
            },
            {
              "icon": "",
              "label": "它悄悄跳过被移除元素后的元素，但其他方面无错误完成"
            },
            {
              "icon": "",
              "label": "它抛 IndexOutOfBoundsException 一旦循环达到列表的旧大小"
            },
            {
              "icon": "",
              "label": "它抛 ConcurrentModificationException — 在一个隐含迭代器走过列表时直接修改列表结构被检测并拒绝；必须使用 Iterator.remove()"
            }
          ]
        },
        {
          "question": "在运行时，给定一个 List<String> list，你通过反射或 instanceof 实际能确定什么关于它的泛型类型参数？",
          "options": [
            {
              "icon": "",
              "label": "你能调用 list.getElementType() 在运行时检索 String.class"
            },
            {
              "icon": "",
              "label": "instanceof List<String> 编译并正确检查元素类型"
            },
            {
              "icon": "",
              "label": "JVM 存储类型参数为隐藏元数据，可通过 list.getGenericType() 访问"
            },
            {
              "icon": "",
              "label": "无 — 泛型类型信息在编译时被擦除，所以在运行时对象只是一个 List，无法恢复它是被声明为 List<String> 还是 List<Integer>"
            }
          ]
        },
        {
          "question": "switch (day) { case 1: case 2: print(\"Weekday\"); break; case 6: print(\"Saturday\"); case 7: print(\"Sunday\"); break; default: print(\"?\"); } 如果 day 是 6，打印什么？",
          "options": [
            {
              "icon": "",
              "label": "只有 Saturday — 每个 case 块在自己的 print 语句后总是停止"
            },
            {
              "icon": "",
              "label": "只有 Sunday — 匹配从 case 6 开始但只有 break 前的最后匹配标签执行"
            },
            {
              "icon": "",
              "label": "什么都不打印，因为 day 6 没有自己 break 直接在它下面的匹配 case"
            },
            {
              "icon": "",
              "label": "Saturday 然后 Sunday — case 6 无 break，所以执行跌入下个 case 的代码在命中后面的 break 前"
            }
          ]
        },
        {
          "question": "Product 类需要一个单个、显然的「自然」按价格排序，加上在代码库不同地方按名称或库存等级排序的能力。哪个组合是正确的设计？",
          "options": [
            {
              "icon": "",
              "label": "实现 Comparable<Product> 三个分别的次，每个排序，让调用方选择哪个 compareTo 运行"
            },
            {
              "icon": "",
              "label": "实现 Comparable<Product> 对自然价格排序，为名称和库存等级排序在别处写分别的 Comparator<Product> 实例"
            },
            {
              "icon": "",
              "label": "对每个排序只用 Comparator，包括价格，因为 Comparable 这里无优势"
            },
            {
              "icon": "",
              "label": "只用 Comparable 加三个过载 compareTo 方法，一个每排序"
            }
          ]
        },
        {
          "question": "方法调用 new FileReader(path)，声明 throws IOException。IOException 继承 Exception 而非 RuntimeException。为了编译你必须做什么？",
          "options": [
            {
              "icon": "",
              "label": "什么都不用 — 编译器只对继承 RuntimeException 的异常强制这个"
            },
            {
              "icon": "",
              "label": "要么在 try/catch 中捕获 IOException，要么对你自己的方法声明 throws IOException — 受检异常必须被显式处理或传播，不像未受检 RuntimeException 子类"
            },
            {
              "icon": "",
              "label": "在 try/catch RuntimeException 中包装调用，因为 IOException 在现代 Java 中自动未受检"
            },
            {
              "icon": "",
              "label": "声明方法为 static — 静态方法不受受检异常处理约束"
            }
          ]
        },
        {
          "question": "try (Resource a = new Resource(\"A\"); Resource b = new Resource(\"B\")) { ... } 使用两个实现 AutoCloseable 的资源。如果 try 块正常结束，它们以什么顺序被关闭？",
          "options": [
            {
              "icon": "",
              "label": "A 先被关闭，然后 B，匹配声明顺序"
            },
            {
              "icon": "",
              "label": "B 先被关闭，然后 A — try-with-resources 按照声明顺序的反向关闭资源"
            },
            {
              "icon": "",
              "label": "两个同时被关闭，因为 try-with-resources 并行化清理"
            },
            {
              "icon": "",
              "label": "只有 B 自动被关闭 — A 仍必须在 finally 块中手工关闭"
            }
          ]
        },
        {
          "question": "int getValue() { try { return 1; } finally { return 2; } } 调用 getValue() 返回什么？",
          "options": [
            {
              "icon": "",
              "label": "1 — try 块的返回值已在 finally 运行前提交，所以 finally 无法改它"
            },
            {
              "icon": "",
              "label": "它在运行时抛异常，因为方法无法从两个地方返回"
            },
            {
              "icon": "",
              "label": "2 — finally 内的 return 语句覆盖并替换已在进行中的任何返回，完全丢弃值 1"
            },
            {
              "icon": "",
              "label": "编译错误 — finally 不允许包含 return 语句"
            }
          ]
        },
        {
          "question": "try { ... } catch (IOException e) { ... } catch (FileNotFoundException e) { ...}，FileNotFoundException 继承 IOException。编译这个会怎样？",
          "options": [
            {
              "icon": "",
              "label": "编译错误 — FileNotFoundException catch 块无法到达因为前一个更通用的 IOException catch 块已经匹配每个 FileNotFoundException"
            },
            {
              "icon": "",
              "label": "它编译正常，更具体的 FileNotFoundException 块在那个精确类型被抛时运行"
            },
            {
              "icon": "",
              "label": "它编译正常，两个 catch 块在 FileNotFoundException 时按顺序都运行"
            },
            {
              "icon": "",
              "label": "编译时正常但当一个 FileNotFoundException 实际发生时抛运行时错误"
            }
          ]
        },
        {
          "question": "一个类有一个 synchronized 实例方法 process() 和一个 synchronized 静态方法 configure()。具体每个锁什么？",
          "options": [
            {
              "icon": "",
              "label": "process() 锁它被调用的具体对象实例的监视器，而 configure() 锁 Class 对象的监视器 — 被每个实例共享"
            },
            {
              "icon": "",
              "label": "两个都锁整个 JVM 的相同单个全局锁，不管实例或类"
            },
            {
              "icon": "",
              "label": "process() 锁 Class 对象，configure() 锁恰好调用它的实例"
            },
            {
              "icon": "",
              "label": "都不实际锁什么除非一个 synchronized 块也在方法体内使用"
            }
          ]
        },
        {
          "question": "字段被声明为 volatile int counter = 0;，多个线程并发运行 counter++ 在它上面。volatile 在这里防止丢失的更新吗？",
          "options": [
            {
              "icon": "",
              "label": "是 — volatile 使字段上的每个操作原子，包括增量"
            },
            {
              "icon": "",
              "label": "否 — volatile 只保证跨线程读看到最新写（可见性）；counter++ 是一个读-修改-写有多个步骤，volatile 对这些步骤做不了什么"
            },
            {
              "icon": "",
              "label": "是，但只对 int 和 long 字段特别地，由于 JVM 如何处理 64 位值"
            },
            {
              "icon": "",
              "label": "否，volatile 也无法为 int 这样的原始类型保证可见性"
            }
          ]
        },
        {
          "question": "接口 A 和接口 B 各声明一个默认方法 describe()。一个类实现两个都且不自己覆盖 describe()。会怎样？",
          "options": [
            {
              "icon": "",
              "label": "编译器自动挑接口 A 的版本，因为它在 implements 子句中列出在前"
            },
            {
              "icon": "",
              "label": "两个版本都运行，一个接一个，描述() 被调用时"
            },
            {
              "icon": "",
              "label": "编译时正常，但当 describe() 首次被调用时抛 AmbiguousMethodException"
            },
            {
              "icon": "",
              "label": "编译错误 — 当两个接口贡献同个默认方法时，实现类必须自己覆盖来解决歧义，因为 Java 不会猜你的意思"
            }
          ]
        },
        {
          "question": "list.stream().filter(x -> x > 0).map(x -> x * 2); 被写出但结果从未赋给像 .collect() 或 .forEach() 这样的终端操作。这行执行时实际发生什么？",
          "options": [
            {
              "icon": "",
              "label": "列表的元素没有任何事发生 — filter 和 map 是惰性中间操作只构建管道描述；无终端操作，那个管道什么都不运行"
            },
            {
              "icon": "",
              "label": "每个元素立即被过滤和映射，恰好好像调用了终端操作"
            },
            {
              "icon": "",
              "label": "只有 filter 立即运行；map 被推迟直到终端操作出现"
            },
            {
              "icon": "",
              "label": "它抛 IllegalStateException，因为流管道要求一个终端操作来编译"
            }
          ]
        }
      ],
      "optionOrderVersion": "0154f9576054ad6f"
    }
  }
}
