code-playpad 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,272 @@
1
+ <!-- GENERATED by scripts/sync-java.mjs from java-online-compiler@0.26.0 (5fe0606077ec6c58e155ad0513a97c00f466bd46). Do not edit. -->
2
+
3
+ > This is the compatibility table of the Java engine that code-playpad ships (engine 0.26.0).
4
+ > Paths such as `tests/…`, `SPEC.md` and `docs/…` refer to the engine's source (`java-engine/` in code-playpad's repository), which is not part of the package.
5
+
6
+ # Compatibility — engine 0.26.0 (Stage A, compact source files, objects, numbers and control flow, collections, lambdas, practice mode, String, format, regex, Math, Random, System, Scanner and IO.readln, inheritance, interfaces, Object, instanceof, enums, records, exceptions, hash order, fixed collections, TreeMap, TreeSet, LinkedList, Stack, lambdas, method references, generic classes and methods, var, annotations, varargs, anonymous classes, streams, subList, local classes, raw types, float, byte and short, pattern matching, sealed classes, BigInteger, BigDecimal, EnumMap, EnumSet, fast I/O, static imports, initializer blocks, text blocks, enum constant bodies, Interface.super)
7
+
8
+ This document records what the engine accepts, what it rejects, and the evidence that it behaves like Java. Every method of every library class, with its status and the tests that call it, is in docs/feature-manifest.json (`npm run manifest`). The reference is Java SE 25 (SPEC.md §4), and what the engine implements is **a documented subset of Java 25**, not "Java 25".
9
+
10
+ Every feature has one status:
11
+
12
+ - **Supported:** parsing, type checking, execution, diagnostics, and tests are all implemented.
13
+ - **Supported with limits:** the same, but the limits are listed here.
14
+ - **Unsupported:** the engine reports "… not supported in this version" and never runs the code with a different meaning.
15
+
16
+ > **Evidence:** everything below is checked against the pinned JDK, Temurin 25.0.4.1 (docs/reference-jdk.md).
17
+ > - **Golden programs:** all 47 in `tests/programs` (the SPEC.md §4.1 Stage A corpus among them) match byte for byte: stdout, stderr, and exit code.
18
+ > - **Recorded snippets:** all 1529 cases in `tests/jdk-cases` match. 1508 match byte for byte (once the JDK's own stack frames are removed, as *Known divergences* explains); the other 21 are listed under *Known divergences*, each with the narrower comparison the tests apply to it.
19
+ > - **Practice corpus:** all 10 Stage 4 programs in `tests/corpus` (docs/practice-corpus.md) run and match.
20
+ > - **Field corpus:** 212 of 223 programs written as learners and solvers write Java, kept whether or not the engine supports them, match the JDK exactly. None runs differently; 10 are rejected as unsupported, 1 stops on an engine limitation and none on the instruction limit (`corpus/REPORT.md`, docs/corpus-harness.md).
21
+
22
+ ## Program structure
23
+
24
+ | Feature | Status | Notes |
25
+ | --- | --- | --- |
26
+ | **Compact source files** (Java 25): top-level methods, fields and classes, with no class declaration | Supported | They form an implicitly declared class named after the file (`Main` for `Main.java`), which the program cannot refer to by name (`Main.f()` is `cannot find symbol`, as in javac). Classes declared in the file are its member classes: inner unless `static`, named `Main$Node` at run time and `Main.Node` in diagnostics, as javac does. |
27
+ | **Several top-level classes** | Supported | Any number, in any order, each with its own fields, methods and constructors. `duplicate class: Node`. A public class need not match the file name (source-file mode allows it). |
28
+ | **Member classes**: `static` nested and inner | Supported with limits | `static class Node` inside `Main`, or an inner class, whose instances hold their enclosing instance (`this$0`) and can use its fields and methods by simple name. `new Inner()` needs an enclosing instance (`non-static variable this cannot be referenced from a static context`). Names: `Main$Node` at run time, `Node` in diagnostics, `Main.Node` as a qualified type. Classes nest to any depth (`static class MyList<T> { class Node { T val; } }`): an inner class reaches each enclosing instance through javac's `this$N` fields, so NPE messages name them as the JDK does. An inner class of a generic class, seen from outside it, keeps its outer class's type variables. `Outer.this` names an enclosing instance. `outer.new Inner()` is unsupported. |
29
+ | **Launch protocol** (Java 25) | Supported | The first top-level class runs if it has a `main`, otherwise the class named after the file (`can't find class: Main` if there is none). `main(String[])` is preferred over `main()`. Either may be `static` or an instance method, and need not be `public` (but not `private`). An instance `main` runs on an instance made with the no-argument constructor, which may be private (`can't find no argument constructor in class: A`). `String... args` and `String args[]` are accepted; `args` is empty. |
30
+ | Methods: parameters, `return`, recursion, overloading; `static` and instance | Supported | Overload resolution follows JLS 15.12.2: the strict phase, then the boxing phase, then the most specific method, with javac's "cannot be applied", "no suitable method", and "ambiguous" reports. Calls are `f(x)`, `this.f(x)`, `obj.f(x)`, `Node.f(x)`, or an enclosing class's `f(x)`. Using an instance member from a static context gives javac's `non-static … cannot be referenced from a static context`. |
31
+ | **Constructors** | Supported with limits | Overloaded, with javac's resolution errors (`constructor Point in class Point cannot be applied to given types;`, `no suitable constructor found for Point(String)`, `reference to Pair is ambiguous`). A class without one gets the default constructor. `this(...)` as the first statement, with `recursive constructor invocation` detected. Statements before `this(...)` (Java 25's flexible constructor bodies) and `super(...)` are unsupported. |
32
+ | `new C(args)` | Supported | Objects have identity: `==`, `!=`, `null`, and `Object.equals(Object)` by reference. |
33
+ | Fields: `static` and instance, `final`, initializers, `this.x`, `obj.x`, `Node.x` | Supported | Defaults are 0, false, null. Instance initializers run at the start of each constructor that does not call `this(...)`, in source order. `final` fields with constant initializers are constants. `illegal forward reference` and `self-reference in initializer` follow JLS 8.3.3. Blank `final` fields must be assigned exactly once by every constructor: `variable y might not have been initialized`, `might already have been assigned`, `might be assigned in loop`, `not initialized in the default constructor`. |
34
+ | **Class initialization** (JLS 12.4) | Supported | Each class initializes on its first active use (`new`, a static method call, a non-constant static field), not at startup; reading a constant does not initialize it. An exception in a static initializer becomes `ExceptionInInitializerError` where the class was first used, with `Caused by:`. |
35
+ | Access | Supported | `private` members are visible within their top-level class, nested classes included: `secret has private access in Box`, `hide() has private access in Box`, `Box() has private access in Box`. `public`, `protected` and package access are equivalent here (one package). |
36
+ | `toString()`, `equals(Object)`, `hashCode()` | Supported | Declared or inherited, they are used wherever the JDK uses them: string conversion and `println`, `HashMap` and `HashSet` keys, `List.contains`. Without them, `Object`'s: `Node@hash` and identity. `super.toString()` is `Object`'s own. `@Override` is checked with javac's reasons. |
37
+ | **Inheritance** (`extends`, JLS 8.1.4) | Supported with limits | A class extends one class of the program: inherited fields and methods, overriding with dispatch on the object's class, `super(...)` (or the implicit `super()`), `super.f()` and `super.x`, covariant return types, field hiding, static methods inherited and hidden. Superclass constructors and field initializers run first, so a superclass constructor calling an overridden method sees the subclass's fields at their defaults, as on the JDK. `abstract` classes and methods, `final` classes and methods, `protected`. javac's errors: `B is not abstract and does not override abstract method f() in A`, `A is abstract; cannot be instantiated`, `cannot inherit from final A`, `f() in B cannot override f() in A` (with `overridden method is final`, `attempting to assign weaker access privileges; was public`, `return type long is not compatible with int`, `overriding method is static`), `cyclic inheritance involving A`, `abstract method f() in A cannot be accessed directly`, `x has private access in A` for a superclass's private member. NPE messages name the receiver's static type (`Cannot invoke "Main$B.f()"`), as the JDK does. A class may also extend the JDK's exception classes (*Exceptions* below). Extending other library classes, extending an inner (non-static) class, and statements before `super(...)` (Java 25's flexible constructor bodies) are unsupported. |
38
+ | **Interfaces** (JLS 9) | Supported with limits | Interfaces of the program, nested or top-level: abstract methods, `default` methods, `static` methods, `private` methods, constants; `extends` among interfaces; a class implementing several. Implementing methods must be `public` (`g() in C cannot implement g() in I`), and two unrelated defaults conflict (`types I and J are incompatible;`). A class may also implement the library's `Comparable<T>`, `Comparator<T>`, `Iterable<T>` and `Iterator<T>`: then sorting, `PriorityQueue`, `Collections.sort`, for-each and `Objects.compare` call its methods as Java code. `Interface.super.f()` calls a direct superinterface's default method (JLS 15.12.3), also from an interface extending it and inside a lambda, with javac's errors: `not an enclosing class: I` (not a direct superinterface, or a static context), `bad type qualifier I in default super call` (`redundant interface I is extended by J`), `abstract method m() in I cannot be accessed directly`, `illegal static interface method call`. `Main.super.f()` in Main is `super.f()`; `Outer.super.f()` for an enclosing class and implementing other library interfaces are unsupported. |
39
+ | The `Object` type | Supported | Variables, parameters, fields, arrays (`Object[]`), returns. Any value converts to `Object` (primitives box). Its methods on any value: `toString()`, `equals(Object)`, `hashCode()` (each dispatched on the value's class: a String compares by content, an `Integer` by value) and `getClass()`. `new Object()`, `wait`, `notify` and `clone` are unsupported. |
40
+ | Casts and `instanceof` (JLS 15.16, 15.20.2) | Supported | Casts between classes, interfaces, library types and arrays, checked as javac checks them (`incompatible types: A cannot be converted to B` for impossible ones) and when they run: `ClassCastException: class Main$A cannot be cast to class Main$B (…)`, as the JDK words it. `(int) object` checks for an `Integer`, then unboxes. `x instanceof T`, raw types included (`x instanceof List`), and the type pattern `x instanceof T t`, whose variable is in scope where the test is true: in `&&`, the `if` or `while` body, after `if (!(x instanceof T t)) return;` (JLS 6.3.1). A store into an array seen through a supertype is checked: `ArrayStoreException: java.lang.String`. A cast the run cannot fully check (`(T) o`, `(T[]) new Object[n]`, `(List<Integer>) o`) checks the erasure and gives javac's `[unchecked] unchecked cast` warning (with `required:`, `found:` and a `where` clause); a cast between different parameterizations (`(List<String>) intList`) is javac's `incompatible types`. Record patterns: `o instanceof Line(Point(int a, int b), var to)`, their variables in scope as a type pattern's are. `instanceof` with a parameterized type (`x instanceof List<Integer>`) is unsupported. |
41
+ | **Enums** (JLS 8.9) | Supported with limits | Nested or top-level, with fields, constructors (with the hidden name and ordinal, so NPE messages say `<parameter3>`), methods, static members, and `implements`. `values()` (a new array each time), `valueOf(String)` (`IllegalArgumentException: No enum constant Main.Color.PURPLE`, `NullPointerException: Name is null`, with the enum's own frame), `name()`, `ordinal()`, `compareTo` (by ordinal), `toString()` (overridable), `getDeclaringClass()`, `equals` and `hashCode` (identity). The constants are made when the enum initializes, before its other static fields; an exception there is `ExceptionInInitializerError`. `switch` on an enum, with simple or qualified labels (`case RED`, `case Color.RED`); a switch expression naming every constant needs no `default`; a null selector fails as the JDK's does (`Cannot invoke "Main$Color.ordinal()"`). Enums are Comparable, so they sort and queue in declaration order. javac's errors: `enum classes may not be instantiated`, `modifier public not allowed here`, `name() in E cannot override name() in Enum`. `EnumMap` and `EnumSet` are supported (see *Library*). Constants with a class body (`PLUS { int apply(int a, int b) { return a + b; } }`): each is an anonymous subclass of the enum (`Main$Op$1`, numbered with the anonymous classes of the constants' arguments, before the members'), with its own fields, methods, `super` calls and initializer blocks; `getClass()` is the body's class and `getDeclaringClass()` the enum, also in EnumMap and EnumSet. An enum may leave abstract methods to its constants' bodies. javac's errors: `<anonymous Main$Op$2> is not abstract and does not override abstract method apply(int,int) in Op`, `Op is abstract; cannot be instantiated` (a constant without a body), `non-static variable symbol cannot be referenced from a static context` (the enum's private members are not inherited by a body), `equals(Object) in <anonymous Main$Op$1> cannot override equals(Object) in Enum`. |
42
+ | **Records** (JLS 8.10) | Supported with limits | Nested or top-level, with components, accessors (generated, or declared: `invalid accessor method in record R`), the canonical constructor (generated, compact `R { ... }` with the fields assigned after its body, or explicit), other constructors (which must call another: `constructor is not canonical, so it must invoke another constructor of class R`), static fields and methods, instance methods, and `implements`. `toString()` (`Point[x=1, y=2]`, components as String.valueOf shows them, with the record's own frame when one fails), `equals` (doubles compared as `Double.compare` does) and `hashCode` (`31 * h + hash(component)`) as the JDK computes them, unless declared. javac's errors: `field declaration must be static`, `cannot assign a value to final variable v`. Generic records (`record Pair<A, B>(A first, B second)`) are supported; so are local records and record patterns (see *Pattern matching*). |
43
+ | `getClass()`, `X.class` | Supported with limits | A `Class` value per class: `getName()` (`Main$Node`, `[I`), `getSimpleName()` (`Node`, `int[]`), `isInterface()`, `isArray()`, printing as `class Main$Node`, and `==` between classes, as `equals` methods use it. `X.class` is a `Class<X>` (so `new EnumMap<>(Day.class)` infers its key type); `Class<?>` may be declared. The reflection methods are unsupported. |
44
+ | Running a file | Supported with limits | Behaves like `java <entry>` in source-file mode. Only the entry file is compiled. |
45
+ | No class / no usable main | Supported | `error: no class declared in source file`; `error: can't find main(String[]) or main() method in class: Main`; `error: can't find class: Main`; for a compact file, `compact source file does not have main method in the form of void main() or void main(String[] args)` |
46
+ | `import`: single-type and on-demand | Supported with limits | `import java.util.List;` and `import java.util.*;` for the supported java.util classes (see *Library*); the java.lang ones need no import. A compact source file sees java.util without imports, as Java 25's implicit `import module java.base` gives it. A wrong name gets javac's error: `package java.utill does not exist`, or `cannot find symbol` with `location: package java.util`. Real JDK classes outside the subset (`BitSet`, `LocalDate`, …) are unsupported where they are used. Classes of java.io, java.math, java.util.function and java.util.stream that the subset has are imported the same way. |
47
+ | `import static`: single and on-demand (JLS 7.5.3, 7.5.4) | Supported | Methods and fields of the supported classes: `import static java.lang.Math.*;`, `import static java.lang.System.out;`, `import static java.util.stream.Collectors.*;`, `import static java.util.Map.entry;`, and member types (`import static java.util.Map.Entry;`). A simple name means the program's own local, field or method first, then a single import, then an on-demand one (JLS 6.4.1). A method of the class or an enclosing one, Object's included, hides every import of that name, so `toString(a)` with `Arrays.*` imported is javac's `method toString in class Object cannot be applied`. Overloads from several on-demand imports are resolved together (`sort(int[])` from Arrays, `sort(List)` from Collections). javac's errors: `reference to MAX_VALUE is ambiguous` (fields, and methods equally specific in two classes), `cannot find symbol` with `symbol: static foo`, a missing class or package, `static import only from classes and interfaces`. Imported constants are constants (switch labels). Importing from a JDK class outside the subset (`TimeUnit`) is fine until a name from it is used, which is unsupported. |
48
+ | Variable-arity methods and constructors (`int... xs`, JLS 8.4.1) | Supported | Chosen in the third phase of overload resolution, as javac chooses (`f(int)` over `f(int...)`, `g(Integer)` over `g(int...)`); the trailing arguments go into a new array, or an array is passed as it is. javac's `varargs parameter must be the last parameter`, `varargs mismatch; …`, and its `[unchecked]` warnings for a parameter type the run cannot check: `Possible heap pollution from parameterized vararg type T` at the declaration and `unchecked generic array creation for varargs parameter of type List<Integer>[]` at the call, unless the method is `@SafeVarargs`. |
49
+ | **Anonymous classes** (JLS 15.9.5) | Supported with limits | `new Comparator<Integer>() { public int compare(...) { ... } }`, `new Shape("sq") { double area() { ... } }`, `new Iterator<>() { ... }`: extending a class of the program (its constructor's arguments passed on) or a built-in exception, or implementing an interface of the program or the library's `Comparable`, `Comparator`, `Iterable`, `Iterator` and functional interfaces (`Runnable`, `Function`, …), with fields, methods, `@Override`, and the diamond inferred from where the object goes. Named as javac names them (`Main$1`, `Main$Holder$1`, `Main$2$1`, in source order per enclosing class), so stack traces, `getClass().getName()` and `<anonymous Main$1>` in diagnostics match; `getSimpleName()` is empty. They capture effectively final locals of the code around them into javac's `val$x` fields (NPE messages say `"this.val$s"`) and use the enclosing instance's members. javac's errors: `<anonymous Main$1> is not abstract and does not override abstract method …`, `anonymous class implements interface; cannot have arguments`, `cannot inherit from final F`, `local variables referenced from an inner class must be final or effectively final`. Extending an inner class or a library class is unsupported. |
50
+ | **Local classes, interfaces, enums and records** (JLS 14.3) | Supported | `class Point { ... }` (or `record Pair(...)`, `enum Dir { ... }`, `interface Shape { ... }`) declared in a block, visible from its declaration to the end of the block. Named as javac names them, `Main$1Point`, numbered per simple name in source order (`Main$1Helper`, `Main$2Helper`), alongside anonymous classes (`Main$1`). A local class in instance code is inner; it captures the locals it uses as `val$x` fields, so NPE messages name `this.val$s`. javac's errors: `cannot find symbol` outside the block, `class A is already defined in method main(String[])`, `local variables referenced from an inner class must be final or effectively final`, `illegal start of expression` for `static class` in a block. |
51
+ | Initializer blocks (JLS 8.6, 8.7) | Supported | `static { ... }` runs once when the class initializes, with the static field initializers in source order (after an enum's constants); `{ ... }` runs in every constructor that does not call `this(...)`, after the superclass constructor, with the instance field initializers in source order. In classes, enums, records (static only), nested, local and anonymous classes (`new Base("x") {{ add(1); }}`). They may declare locals, loop, catch and use lambdas (`lambda$static$0`, `lambda$new$0`), and assign blank `final` fields, with javac's definite-assignment errors across blocks and constructors. An exception in a static block is `ExceptionInInitializerError`, then `NoClassDefFoundError: Could not initialize class`, as on the JDK. javac's errors: `return outside method`, `initializer must be able to complete normally`, `illegal forward reference`, `unreported exception` (an instance block may throw what every constructor declares), `initializers not allowed in interfaces`, `instance initializers not allowed in records`. |
52
+ | **Generic classes, interfaces, records and methods** (JLS 8.1.2, 8.4.4) | Supported with limits | `class Node<T>`, `class BST<K extends Comparable<K>, V> implements Iterable<K>`, `interface Fn<A, B>`, `static <T extends Comparable<? super T>> void sort(T[] a)`, `<R> Pair<K, R> withValue(R r)`. Members are seen through the type arguments (`T val` of a `Node<Integer>` is an `Integer`; a type variable's members are its bound's), supertypes are parameterized (`class Strs extends Base<String>`, with the bridge methods javac generates so overriding dispatches), the diamond and generic methods are inferred from the arguments, the target, implicit lambdas' bodies and the parameter a diamond is passed to, and explicit type arguments (`Main.<Integer>repeat(7, 2)`) work. Bounds are checked: `type argument String is not within bounds of type-variable T`, `inference variable T has incompatible bounds` (with javac's `upper bounds`, `lower bounds` and `equality constraints` lines), `cannot infer type arguments for Box<>`. javac's other errors: `non-static type variable T cannot be referenced from a static context`, `generic array creation`, `unexpected type` for `new T()`, `wrong number of type arguments`, `name clash: … have the same erasure`, `cannot use '<>' with non-generic class`. Every diagnostic that names a type variable ends with javac's `where T is a type-variable:` clause. As javac does, a generic member's value is checked against the type it has where it is used, so `Integer[] a = box.items` fails with the JDK's `ClassCastException` when the array is really an `Object[]`. Raw types of the program's generic classes are supported as the library's are (see *Generic types at use sites*). Generic constructors are unsupported. |
53
+ | Annotations (JLS 9.7) | Supported with limits | `@Override`, `@SuppressWarnings` (a string or an array of them; `"unchecked"` and `"deprecation"` silence those warnings on the class, method, field or local declaration, and `"all"` silences nothing, as in the source launcher), `@FunctionalInterface` (javac's `Unexpected @FunctionalInterface annotation` with its reason), `@SafeVarargs` (javac's `Invalid SafeVarargs annotation` errors) and `@Deprecated` (`since`, `forRemoval`; on a local variable, javac's `[deprecation] … has no effect on this variable declaration` warning), on classes, methods, constructors, fields, parameters and locals. javac's errors: `cannot find symbol` for an unknown annotation, `annotation interface not applicable to this kind of declaration`, `… is not a repeatable annotation interface`, `annotation @SuppressWarnings is missing a default value for the element 'value'`, `incompatible types` for a non-String value. Other annotations (the JDK's, or declared with `@interface`), annotations on types and type arguments, and values other than literals are unsupported. |
54
+ | Warnings | Supported | javac's `[unchecked]` and `[deprecation]` warnings, as the source launcher prints them: before the program's output on a run, among the errors in source order when compilation fails, and counted (`1 warning`, `2 warnings`) after the errors. |
55
+ | `package`, declaring annotation interfaces | Unsupported | |
56
+
57
+ ## Types and values
58
+
59
+ | Feature | Status | Notes |
60
+ | --- | --- | --- |
61
+ | `int` | Supported | 32-bit two's complement: overflow wraps, `/` truncates, `%` takes the dividend's sign, `MIN_VALUE / -1` wraps. `/ by zero` throws. Shift distances are masked. |
62
+ | `char` | Supported | A UTF-16 code unit (0–65535). Arithmetic promotes to `int` (`'a' + 1` is `98`). `char c = 65` is allowed because the constant fits. `c = c + 1` is an error ("possible lossy conversion"), while `c += 1` and `c++` wrap. |
63
+ | `long` | Supported | 64-bit two's complement, like `int`: wrapping, truncating `/`, `/ by zero`, `MIN_VALUE / -1`, shifts masked to 6 bits, `>>>`. Literals with `L`, in any radix, with underscores (`integer number too large`). Long values stay exact past 2^53 (engine numbers become BigInts there, an implementation detail). |
64
+ | `double` | Supported | IEEE 754 binary64, as Java: `NaN`, infinities, `-0.0`, `%` as fmod, division by zero giving `Infinity`. Literals in decimal and hexadecimal (`0x1.8p1`), with `d`/`D`, `floating-point number too large` / `too small`. Printed exactly as `Double.toString` (`0.30000000000000004`, `1.0E7`, `9.999E-4`, `4.9E-324`). |
65
+ | Numeric promotion and conversions (JLS 5.1–5.6) | Supported | Widening in assignment, invocation, and operators (`int` + `long` is `long`, anything with `double` is `double`); casts in every direction with Java's rules (`(int) 1e300` saturates, `(int) NaN` is 0, `(char) 65601L` keeps the low bits); compound assignment's implicit cast (`long l = 5; l += 2.7;` is `7`); `possible lossy conversion from long to int`. Constant expressions fold with the same arithmetic. |
66
+ | `boolean` | Supported | |
67
+ | `String` | Supported with limits | Literals and text blocks (`"""`, JLS 3.10.6: the incidental indentation and trailing spaces are stripped, line ends become `\n`, and escapes, `\s` and the line-joining `\<newline>` included, are interpreted last; javac's `illegal text block open delimiter sequence, missing line terminator`, `unclosed text block`, `illegal escape character`), `null`, concatenation with any supported type, and `==` by reference (constants are interned). Methods: see the Library section; `new String(...)` makes a new object, so `new String("a") == "a"` is `false`. Contents are arbitrary Unicode (UTF-16). |
68
+ | Wrapper classes: `Integer`, `Long`, `Double`, `Character`, `Boolean` | Supported with limits | Boxing and unboxing (JLS 5.1.7–5.1.8) in assignment, invocation, operators, `?:`, compound assignment and `++`/`--`. `==` compares references, and the JDK's caches are reproduced (`Integer` and `Long` -128 to 127, `Character` 0 to 127, both `Boolean`s): `Integer a = 127, b = 127;` gives `a == b` true, and 128 gives false. Unboxing null is the JDK's NPE, `Cannot invoke "java.lang.Integer.intValue()" because …`. A switch on a wrapper is unsupported. |
69
+ | Generic types at use sites: `List<Integer>`, `Map<String, List<Integer>>`, `new ArrayList<>()` | Supported with limits | Type arguments are checked as javac checks them: invariance (`ArrayList<Integer> cannot be converted to List<String>`), `unexpected type` with `required: reference` for `List<int>`, and `wrong number of type arguments`. The diamond is inferred from the target type, the constructor's arguments, or the parameter it is passed to. Types print as javac prints them (`Map<String,Integer>`). Wildcards (`List<?>`, `List<? extends T>`, `Comparator<? super T>`) are supported: a value read through one has its bound's type, and a parameter of `? super T` takes a `T`. Generic array creation is javac's error, except of raw types (`new ArrayList[n]`, `new List[n]`) and unbounded wildcards (`new List<?>[n]`); a raw array assigned, returned or initialized as `List<Integer>[]` is javac's `[unchecked] unchecked conversion` warning. Raw types (`List raw = new ArrayList();`, `Map m`, `Box b = new Box("s")`, `(List) o`, `o instanceof List`) are supported: their members are erased (`raw.get(0)` is an `Object`), and javac's warnings are reported: `[unchecked] unchecked call to add(E) as a member of the raw type List`, `unchecked conversion` (raw to parameterized), `unchecked method invocation`, `unchecked assignment to variable v as member of raw type Box`, each with its `where` clause, and silenced by `@SuppressWarnings("unchecked")`. An argument that converts only unchecked makes the call `unchecked method invocation` and its type erased (`new ArrayList<>(raw)` is a raw `ArrayList`). As on the JDK, heap pollution through a raw type fails where the value is used (`int v = ints.get(0)` of a `String` is a `ClassCastException`). Generic calls are target-typed as javac types them: arguments bound a type variable from below (`List.of(1, 2.5)` is a `List<Number>`, `List.of(new Sq(1), new Circle(2))` a `List<Shape>` when both implement `Shape`), and an assignment, return or parameter that names the type argument decides it (`List<Shape> s = List.of(new Sq(1))`, `take(List.of(new Sq(1)))`), with javac's `inference variable E has incompatible bounds` when an argument does not fit. The engine has no intersection types: where javac infers one (`List.of(1, "a")` with no target), it keeps a common class or interface, or Object. |
70
+ | The program's classes as types | Supported | `Node n = new Node(1);`, parameters, return types, fields. `incompatible types: Bag cannot be converted to Box`, `incomparable types: Box and Bag`. |
71
+ | Arrays of any supported type, any number of dimensions | Supported | `new T[n]`, `new int[3][4]`, `new int[3][]` (jagged), `new T[]{…}`, nested `{{…}, {…}}` initializers, `a[i][j]`, and `.length`. Arrays are default-initialized, bounds-checked, and compared by reference. `int a[]` and `int[] a[]` declarations are accepted. They print with JVM descriptors: `[[I@hash`, `[J@hash`, `[LNode;@hash`. |
72
+ | Casts between `int` and `char`, and identity casts | Supported | `(char) 65601` keeps the low 16 bits. A cast from boolean to int is an error, as in Java. |
73
+ | `var` (JLS 14.4.1) | Supported | For locals, `for` and enhanced-`for` variables and resources: the type of the initializer (a diamond nothing decides is `Object`'s, `new ArrayList<>()` an `ArrayList<Object>`). javac's errors: `cannot infer type for local variable x` with `(variable initializer is 'null')`, `(lambda expression needs an explicit target-type)`, `(method reference needs an explicit target-type)`, `(array initializer needs an explicit target-type)`, `(cannot use 'var' on variable without initializer)` and `(cannot use 'var' on self-referencing variable)`; `'var' is not allowed in a compound declaration`, `… as an element type of an array`, and `'var' is not allowed here` for a field. `var` lambda parameters are unsupported. |
74
+ | `float` (JLS 4.2.3) | Supported | IEEE 754 binary32, as Java: every operation is the double one rounded once to float (exact for `+ - * / %`), and `long` → `float` rounds once (`(float) 9007199254740993L` is `9.007199E15`). Literals with `f`/`F`, decimal or hexadecimal, rounded once and correctly (`1.0000000596046447753906250001f` is `1.0000001`), with `floating-point number too large` / `too small`. Printed as JDK 19+'s `Float.toString` (the shortest decimal that rounds back, computed exactly: 3,000 random floats print as on JDK 25). Promotion, widening and javac's `possible lossy conversion from double to float` as JLS 5.1–5.6 say; `Math.abs`, `max`, `min`, `round` (an `int`), `signum`, `ulp`, `nextUp`, `nextDown`, `clamp` of floats; `float[]`. A `switch` on a float is javac's `primitive patterns are a preview feature`. |
75
+ | `byte`, `short` (JLS 4.2.1) | Supported | Promoted to `int` in arithmetic; `b += 120` and `b++` narrow back, wrapping as Java does; `(byte) 300.5f` goes through `int`. A constant that fits may be assigned without a cast (`byte b = 10;`, `short s = 'B';`, `Byte b = 100;`), others are javac's `possible lossy conversion from int to byte`. `byte[]`, `short[]`, `switch` on either (a label out of range is a lossy-conversion error), and JLS 15.25's conditional typing (`byte` with `short` is `short`). |
76
+
77
+ ## Statements and expressions
78
+
79
+ | Feature | Status | Notes |
80
+ | --- | --- | --- |
81
+ | Blocks; local variables (several declarators, `final`); `;` | Supported | Blank `final` locals are unsupported. |
82
+ | `if`/`else`, `while`, `do`/`while`, basic `for` (declaration or expression-list init, comma updates) | Supported | |
83
+ | Enhanced `for` over arrays | Supported | Element conversions as in Java (`for (long w : intArray)`). Its three hidden locals are allocated where javac puts them, so NPE messages name the same slots (`"<local7>"`), and a null array is reported as the hidden copy (`"<local2>"`). `for-each not applicable to expression type`. |
84
+ | Enhanced `for` over an `Iterable` (any collection) | Supported | Through an iterator in one hidden local, as javac compiles it. A null collection is `Cannot invoke "java.util.List.iterator()" because "<local1>" is null`, and unboxing a null element is `… because the return value of "java.util.Iterator.next()" is null`. |
85
+ | `break`, `continue` (labeled and unlabeled), labeled statements, `return` | Supported | `break outside switch or loop`, `continue outside of loop`, `undefined label: x`, `not a loop label: block`, `label x already in use`, `missing return statement`, `unexpected return value`, `missing return value` |
86
+ | `switch` statements and expressions (JLS 14.11, 15.28) | Supported with limits | Over `int`, `char` and `String`, in the `:` form (with fall-through) and the `->` form, several labels per case, `yield`. A String switch has javac's two hidden locals (a null selector fails as `Cannot invoke "String.hashCode()"`). Checked as javac does: `duplicate case label`, `constant expression required`, `different case kinds used in the switch`, `the switch expression does not cover all possible input values`, `switch rule completes without providing a value`, `bad type in switch expression`, `yield outside of switch expression`, `attempt to break out of a switch expression`; a `long`/`double`/`boolean` selector gives Java 25's preview-feature error. A rule may be `throw` (`default -> throw new IllegalArgumentException()`). Also over `byte`, `short`, enums with simple or qualified labels (`case Color.GREEN`), and, with patterns, any reference type (see *Pattern matching*). |
87
+ | **Pattern matching** (JLS 14.11.1, 14.30, 15.20.2) | Supported with limits | `switch` with type patterns (`case Circle c ->`), guards (`case Integer i when i > 0`), record patterns, nested and with `var` (`case Line(Point(var x, var y), Point p)`), the unnamed pattern `_`, `case null` and `case null, default`, constants alongside patterns (String, wrapper and enum constants, qualified enum constants on a sealed interface), in both forms and as statements or expressions. Cases are tried in order; a pattern's variables are in scope in its guard and body only; a record pattern calls the accessors, and its nested patterns that cover their component match null. A null selector without `case null` is the JDK's `NullPointerException`. Exhaustiveness as JLS 14.11.1.1 defines it: a default, an unconditional pattern, every permitted subclass of a sealed type (recursively), every enum constant, or record patterns covering every combination of their components (`the switch expression does not cover all possible input values`, also for a pattern switch statement). javac's other errors: `this case label is dominated by a preceding case label`, `switch has both an unconditional pattern and a default label`, `illegal fall-through to a pattern`, `deconstruction patterns can only be applied to records`, `incorrect number of nested patterns`, a guard that is constant `false`, and the preview error for primitive patterns. Several patterns in one label (`case A _, B _`) are unsupported. |
88
+ | **Sealed classes and interfaces** (JLS 8.1.1.2, 9.1.1.4) | Supported | `sealed` with a `permits` clause, or without one, permitting the file's classes that extend it; `non-sealed`; records and enums as permitted subclasses. javac's errors: `class is not allowed to extend sealed class: S (as it is not listed in its 'permits' clause)`, `sealed, non-sealed or final modifiers expected`, `invalid permits clause` (with its reason), `sealed class must have subclasses`, `non-sealed modifier not allowed here`, `illegal combination of modifiers: final and sealed`, `local classes must not extend sealed classes`, `anonymous classes must not extend sealed classes`, and a sealed interface is not a functional interface. |
89
+ | `throw`, `try`/`catch`/`finally`, multi-catch (JLS 14.18, 14.20) | Supported | `catch` matches the thrown object's class, inner handlers first; `finally` runs on every way out: normally, by an exception, `return` (after the value is computed), `break` and `continue`. A `return` or exception in `finally` replaces the one in flight, as in Java. `throw null` is `Cannot throw exception because "<local1>" is null`. javac's slots are kept: a catch parameter and each copy of a `finally` block get the slots javac gives them, so NPE messages name the same `<localN>`. javac's errors: `exception X has already been caught`, `Alternatives in a multi-catch statement cannot be related by subclassing`, `multi-catch parameter e may not be assigned`, `'try' without 'catch', 'finally' or resource declarations`, `incompatible types: String cannot be converted to Throwable`. |
90
+ | Try-with-resources (JLS 14.20.3) | Supported | Resources are a program class implementing `AutoCloseable`, a `Scanner`, a java.io reader or writer, or an effectively final variable. They close in reverse order, also when the block throws; an exception from `close()` is added to the one in flight with `addSuppressed`, and printed as `Suppressed:`. `try-with-resources not applicable to variable type`. |
91
+ | Checked exceptions (JLS 11.2) | Supported | Checked as javac checks them, after its other flow errors: `unreported exception X; must be caught or declared to be thrown` (also for the implicit `close()` of a resource), `exception X is never thrown in body of corresponding try statement`, `overridden method does not throw X`. Library methods declare theirs (`BufferedReader.readLine() throws IOException`). `throws` clauses, and precise rethrow: `catch (Exception e) { throw e; }` throws only what the block can throw. |
92
+ | `assert` | Supported | Checked, and not run: `java Main.java` runs with assertions disabled. |
93
+ | `synchronized` methods | Supported | No effect, since a program has one thread; javac's errors for them are kept. `synchronized` statements are unsupported. |
94
+ | All `int` operators, `char` arithmetic, comparison, `&&`/`\|\|`, `++`/`--` on locals, fields and array elements, every compound assignment | Supported | Operands are evaluated left to right; `a[i++] += 5` evaluates `a` and `i` once. |
95
+ | `new C(args)` as a statement | Supported | JLS 14.8. |
96
+ | `?:` (JLS 15.25) | Supported with limits | Two booleans give a boolean; numbers follow the table (`t ? 'a' : 0` is a `char`, `t ? 'a' : i` an `int`, `t ? 1 : 2L` a `long`). Reference operands are checked against the assignment or return type (`incompatible types: bad type in conditional expression`), otherwise their type is the common one. Constant conditionals fold. A primitive with a reference boxes or unboxes as JLS 15.25 says (`t ? 1 : null` is an `Integer`). A boolean with a number is unsupported. |
97
+ | `this` | Supported | |
98
+ | Lambda expressions (JLS 15.27) | Supported with limits | `x -> expression`, `(a, b) -> { statements }`, with parameter types inferred from the target or written out exactly, for any functional interface: the library's (`Comparator`, `Runnable`, `java.util.function`'s `Function`, `BiFunction`, `Supplier`, `Consumer`, `BiConsumer`, `Predicate`, `BiPredicate`, `UnaryOperator`, `BinaryOperator`, the `Int…`, `Long…`, `Double…` and `To…` forms) or the program's own (an interface with one abstract method, whose default methods then run on the lambda). **Captures:** effectively final locals and parameters of the code around it, and `this` with instance members; javac's `local variables referenced from a lambda expression must be final or effectively final` and `might not have been initialized`. Each compiles to a synthetic method named as javac names it (`lambda$main$0`, `lambda$static$0`, `lambda$new$0`), its captured variables passed first in order of first use, so stack traces and NPE messages (`"<parameter2>"`) match. A lambda that captures nothing is one object; one that captures is a new object each time. javac's errors: `incompatible parameter types in lambda expression`, `bad return type in lambda expression`, `lambda body is not compatible with a void functional interface`, `X is not a functional interface` (with `multiple non-overriding abstract methods found` or `no abstract method found`), `lambda expression not expected here`. Generic methods infer their type arguments from lambdas as javac does where the target or the lambda decides (`Comparator.comparing(p -> p.age())` inside `list.sort(...)`; as a receiver of `.reversed()` the lambda's parameter is an `Object`, as in javac). The program's generic interfaces are targets too (`Transformer<String, Integer> len = String::length`). Lambdas implementing `Iterable` are unsupported. |
99
+ | Method references (JLS 15.13) | Supported | `Integer::compare`, `String::length`, `Main::helper`, `this::visit`, `super::toString`, `list::add`, `System.out::println`, `ArrayList::new`, `int[]::new`, `String[]::new`. They resolve as javac resolves them (a static method taking every parameter, or an instance method of the first), with javac's `invalid method reference` errors (`cannot find symbol`, `reference to … is ambiguous`, `unexpected instance method … found in unbound lookup`, `bad return type in method reference`). As on the JDK they have no frame of their own, and a null receiver is a `NullPointerException` without a message. An exact reference (`Person::age`) decides a generic method's type arguments (`Comparator.comparing(Person::age).reversed()`); one to a generic class's method (`Pair::first`, `Box::get`) takes its types from the receiver the function type has. Explicit type arguments (`Foo::<T>bar`) and references on a parameterized type (`Pair<String, Integer>::first`) are unsupported. |
100
+
101
+ ## Library
102
+
103
+ | API | Status | Notes |
104
+ | --- | --- | --- |
105
+ | `IO.println(Object)`, `IO.println()`, `IO.print(Object)` (`java.lang.IO`, Java 25) | Supported | Arguments box, so `IO.println(42)` and `IO.println('c')` work. An array prints as `type@hash` (even a `char[]`, unlike `System.out.println`). The output goes to System.out. |
106
+ | `IO.readln()`, `IO.readln(String prompt)` (Java 25) | Supported | Reads a line of standard input (below), ended by `\n`, `\r` or `\r\n`, without its terminator; `null` at the end of input. The prompt is printed first, without a newline (`null` prints as `null`). |
107
+ | Standard input (`System.in`) | Supported with limits | The run's input is given in full before it starts (code-playpad's input box); reading never waits or prompts, as with input piped to `java Main.java`. A program that reads past the end gets the JDK's exception, and the run result carries a hint about the input box (`hintAbout: 'stdin'`). `System.in` can be passed to a `Scanner` or an `InputStreamReader`; its own methods (`read`, …) are unsupported. One reader per run: a second `Scanner` or `BufferedReader` over `System.in`, or `IO.readln` together with either, is an engine limitation (below). |
108
+ | `java.util.Scanner` | Supported with limits | Over `System.in` or a `String`: `next`, `nextLine`, `nextInt`, `nextLong`, `nextDouble`, `nextBoolean`, their `hasNext…` forms, `hasNextLine`, `close`. Tokens are separated by Java's default delimiter (every `Character.isWhitespace` character, such as U+2003 but not the no-break space U+00A0), and `nextLine` ends lines at `\r\n`, `\n`, `\r`, U+2028, U+2029 and U+0085, so `nextInt()` followed by `nextLine()` returns the rest of the line, often empty, as in Java. The JDK's exceptions: `NoSuchElementException` (`No line found` from `nextLine`), `InputMismatchException` without consuming the token (`For input string: "99999999999"` when out of range), `IllegalStateException: Scanner closed`. Numbers are read as under the reference JDK's English locale (owner decision, 2026-10-18): a sign, digits with optional `,` group separators in groups of three (`1,234,567`; `12,34` is not a number), and for doubles a `.` decimal point, an exponent, `NaN`, `Infinity`, or the locale's `∞` (which matches and then fails to parse, as on the JDK). Hexadecimal floating point (`0x1.8p1`) is read as Java reads it; non-ASCII digits are an engine limitation. `nextFloat`, `nextByte` and `nextShort` (and their `hasNext…` forms) read as the JDK does, with Byte's and Short's `Value out of range. Value:"200" Radix:10`. Radix overloads, `useDelimiter`, `findInLine` and the rest are unsupported. |
109
+ | `java.io.BufferedReader`, `InputStreamReader`, `StringReader` | Supported | Over `System.in` or a `String`: `readLine` (lines end at `\n`, `\r` or `\r\n`; null at the end), `read()`, `read(char[][, off, len])` (everything requested that the input has), `ready`, `skip`, `lines()` (read when the stream's terminal operation runs), `close`. They throw `IOException`, which must be caught or declared (`unreported exception IOException`). After `close`: `IOException: Stream closed`. Their messages for bad arguments are the JDK's (`Range [2, 2 + 5) out of bounds for length 4`, `Buffer size <= 0`). Charsets, `mark` and `reset` are unsupported. |
110
+ | `java.io.PrintWriter`, `BufferedWriter`, `OutputStreamWriter`, `StringWriter` | Supported | Over `System.out`, `System.err`, each other, or a `StringWriter`: every `print`/`println` overload, `printf`, `format`, `write`, `append`, `newLine`, `flush`, `close`, `checkError`, autoflush. They buffer as the JDK's do (ADR 0016): what is not flushed when the program ends is lost, and exactly the part the JDK writes out reaches the output (4,000 unflushed lines print their first 24,576 bytes). `PrintWriter` never throws `IOException`; the others do, after `close`. File names and charsets are unsupported, as is `StringWriter.getBuffer()`. |
111
+ | `java.util.StringTokenizer` | Supported | `hasMoreTokens`, `nextToken`, `nextToken(delimiters)`, `hasMoreElements`, `nextElement`, `countTokens`; the default delimiters `" \t\n\r\f"`, custom ones, and returning delimiters as tokens. `NoSuchElementException` at the end; the JDK's `NullPointerException`s for a null string or delimiters. |
112
+ | `java.io.StreamTokenizer` | Supported with limits | `nextToken`, the public fields `ttype`, `nval` and `sval`, `TT_EOF`, `TT_EOL`, `TT_NUMBER`, `TT_WORD`, `pushBack`, `lineno`, `toString`, and the syntax methods (`wordChars`, `whitespaceChars`, `ordinaryChar(s)`, `commentChar`, `quoteChar`, `parseNumbers`, `resetSyntax`, `eolIsSignificant`, `lowerCaseMode`). Numbers have the JDK's exact values, including its rounding of long digit strings. `slashStarComments` and `slashSlashComments` are unsupported. |
113
+ | `System.out` / `System.err`: `print` and `println` | Supported | Overloads are resolved as in javac across all nine (`println` also has a no-argument form): `println('x')` prints the char, `println(charArray)` prints the characters, and other arrays print as `type@hash`. `println(null)` is ambiguous, as in Java. |
114
+ | `System.out` / `System.err` as values; `flush()`, `close()`, `checkError()` | Supported | Passed to `PrintWriter` or `OutputStreamWriter` as the `OutputStream` they are. `System.out` prints at once, so `flush()` has nothing to do. Closing it, directly or through a writer over it, drops everything printed to it afterwards, as on the JDK; a closed `System.err` drops an uncaught exception's trace too. `PrintStream` as a declared type, `write` and `append` are unsupported. |
115
+ | `System.out` / `System.err`: `printf(String, Object...)`, `format(String, Object...)` | Supported with limits | As `String.format`, below. The call is a statement: the `PrintStream` it returns cannot be used (`System.out.printf(...).println()` is unsupported). The `Locale` overloads are unsupported. |
116
+ | `String.length()`, `charAt(int)`, `equals(Object)`, `isEmpty()`, `toCharArray()`, `compareTo(String)` | Supported | `equals` boxes primitives, so `"x".equals(5)` is `false`, as in Java. `compareTo` gives the JDK's values (the first differing character's difference, else the length difference) and its NPE messages. These need no Java library. |
117
+ | Other `String` methods | Supported | `substring`, `indexOf` and `lastIndexOf` (of a `String` or a character, from an index), `contains`, `startsWith`, `endsWith`, `toUpperCase`, `toLowerCase`, `trim`, `strip`, `stripLeading`, `stripTrailing`, `isBlank`, `repeat`, `lines` (a `Stream<String>`, lines ended by `\n`, `\r` or `\r\n`), `stripIndent`, `translateEscapes` (`Invalid escape sequence: \q \\u0071`), `indent`, `replace` (chars or strings), `equalsIgnoreCase`, `compareToIgnoreCase`, `concat`, `hashCode`, `toString`, `split` (with and without a limit), `replaceAll`, `replaceFirst`, `matches`, `formatted`; statics `valueOf` (every supported type, `char[]` and a range of one), `copyValueOf`, `format`, `join` (varargs, an array, or an `Iterable` such as a `List<String>`); constructors `()`, `(String)`, `(char[])`, `(char[], int, int)`, `(StringBuilder)`. The JDK's exceptions and NPE messages: `Range [4, 3) out of bounds for length 3` (from `"abc".substring(4)`), `Range [1, 1 + 5) out of bounds for length 2`, `count is negative: -1`, `Cannot invoke "String.isEmpty()" because "this.pattern" is null`. `split` follows Java's rules (no leading empty string from a zero-width match, trailing empty strings removed when the limit is 0). Case mapping is the JDK's root-locale mapping (`"straße".toUpperCase()` is `STRASSE`). Parameters the JDK declares as `CharSequence` take a `String` here. `chars`, `lines`, `getBytes`, `intern`, `codePointAt` and the other methods are unsupported. |
118
+ | Regular expressions (`split`, `replaceAll`, `replaceFirst`, `matches`) | Supported with limits | Java's syntax, translated to JavaScript's engine with Java's meanings: `.` and `$` know Java's line terminators (including `\r\n` and U+0085), `\s` is ASCII whitespace, `\h`, `\v`, `\R`, `\A`, `\z`, `\Z`, `\Q…\E`, POSIX classes (`\p{Alpha}`, `\p{Upper}`, …), named groups and back references, a leading `(?i)` or `(?s)`. Replacements as Java reads them: `$1`, `${name}`, `\$`, with `IllegalArgumentException: Illegal group reference` and `No group 2`. Malformed patterns are `PatternSyntaxException` with the JDK's description, index and caret (`Unclosed group near index 1`, `Dangling meta character '*' near index 0`). Constructs that do not translate exactly are engine limitations (below). `java.util.regex.Pattern` and `Matcher` are unsupported. |
119
+ | `String.format`, `formatted` | Supported with limits | Conversions `%d %o %x %X %s %S %c %C %b %B %h %H %e %E %f %g %G %n %%`, with argument indexes (`%2$s`, `%<s`), flags (`-#+ 0,(`), width and precision. Floating point rounds as Java's Formatter does, half-up on the shortest decimal: `%.2f` of `1.005` is `1.01` (C's printf gives `1.00`). The JDK's exceptions: `IllegalFormatConversionException: d != java.lang.String`, `MissingFormatArgumentException: Format specifier '%d'`, `UnknownFormatConversionException: Conversion = 'q'`, `FormatFlagsConversionMismatchException`, and others. Date and time (`%t`) and hexadecimal floating point (`%a`) are engine limitations; the `Locale` overloads are unsupported. |
120
+ | `Math.abs`, `max`, `min` (int, long, double), `sqrt`, `floor`, `ceil`, `round(double)`, `Math.PI`, `Math.E` | Supported | Resolved against all of Math's overloads, so `Math.max(1, 2L)` is the long one and errors list every candidate as javac does. `Math.abs(Integer.MIN_VALUE)` is `MIN_VALUE`; `Math.round` rounds half up and saturates. These need no Java library. |
121
+ | Other `Math` methods | Supported with limits | `pow`, `exp`, `log`, `log10`, `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2`, `sinh`, `cosh`, `tanh`, `cbrt`, `hypot`, `expm1`, `log1p`, `toRadians`, `toDegrees`, `signum`, `rint`, `ulp`, `nextUp`, `nextDown`, `random`; exact integer arithmetic (`addExact`, `subtractExact`, `multiplyExact`, `incrementExact`, `decrementExact`, `negateExact`, `toIntExact`, `absExact`) with `ArithmeticException: integer overflow` / `long overflow`; `floorDiv`, `floorMod` (`/ by zero`); `clamp` (`IllegalArgumentException: 5 > 2`). The transcendental functions may differ from the JDK in the last digit (see Known divergences). Their float overloads too. `fma`, `copySign`, `scalb`, `ceilDiv` and the rest are unsupported. |
122
+ | `System` methods | Supported | `currentTimeMillis`, `nanoTime`, `exit`, `arraycopy`, `lineSeparator` (`"\n"`), `identityHashCode`. `System.exit(n)` ends the run at once and prints nothing, as the JDK does; the run's exit code is `n` (status `exited` when `n` is not 0, `success` when it is). `arraycopy` has the JDK's checks and messages: `arraycopy: last source index 8 out of bounds for int[5]`, `arraycopy: type mismatch: can not copy int[] into long[]`, and overlapping copies within one array. `getProperty`, `getenv`, `setOut` and the others are unsupported. |
123
+ | `java.util.Objects` | Supported | `equals`, `hash` (`Arrays.hashCode` of its arguments, calling their `hashCode()`), `hashCode`, `toString` (with a default), `isNull`, `nonNull`, `requireNonNull` (with a message), `requireNonNullElse`, `checkIndex` (`Index 5 out of bounds for length 3`), `compare` with a comparator. |
124
+ | `java.util.Random` | Supported with limits | `nextInt()`, `nextInt(bound)`, `nextInt(origin, bound)`, `nextLong()` (and its bounded forms), `nextDouble()` (and its bounded forms), `nextBoolean`, `nextGaussian()`, `setSeed`; constructors `()` and `(long seed)`. A seeded generator produces exactly the JDK's sequence (the 48-bit generator the API documentation specifies). An unseeded one, like `Math.random()`, is unpredictable, as on the JDK. `nextFloat()`. The `ints`/`doubles` streams and `nextGaussian(mean, stddev)` are unsupported. |
125
+ | `Integer.MAX_VALUE`/`MIN_VALUE`/`SIZE`/`BYTES`, `Long.MAX_VALUE`/`MIN_VALUE`/`SIZE`/`BYTES`, `Character.MAX_VALUE`/`MIN_VALUE`/`MIN_RADIX`/`MAX_RADIX`/`SIZE`/`BYTES`, `Double.MAX_VALUE`/`MIN_VALUE`/`MIN_NORMAL`/`POSITIVE_INFINITY`/`NEGATIVE_INFINITY`/`NaN`/`SIZE`/`BYTES` | Supported | Constants, folded like any constant. Using one does not load the Java library. |
126
+ | `ArrayList`, `List` | Supported | `add(E)`, `add(int, E)`, `get`, `set`, `remove(int)`, `remove(Object)`, `size`, `isEmpty`, `contains`, `indexOf`, `lastIndexOf`, `clear`, `addAll`, `containsAll`, `iterator`, `getFirst`, `getLast`, `removeFirst`, `removeLast`, `addFirst`, `addLast`, `sort(Comparator)` (natural order for null; it counts as a change, so sorting inside a for-each over the list is a `ConcurrentModificationException`), `subList` (a view: changes go through to the list and back, a structural change to the list makes the view throw `ConcurrentModificationException`, the JDK's range messages `fromIndex = -1`, `toIndex = 4`, `fromIndex(2) > toIndex(1)`; on every list kind, with the JDK's class names, `ArrayList$SubList`, `AbstractList$SubList` for `LinkedList`, `ImmutableCollections$SubList` for `List.of`, `AbstractList$RandomAccessSubList` for `Arrays.asList`), `equals`, `hashCode`, `toString`. Constructors `()`, `(int)`, `(Collection)`. Overload resolution decides as javac does: `list.remove(1)` removes at an index, `list.remove(Integer.valueOf(1))` removes an element. The JDK's exceptions: `Index 5 out of bounds for length 1`, `Index: 3, Size: 2` from `add(int, E)`, `Illegal Capacity: -1`. The iterator fails fast exactly as the JDK's does: removing the second-to-last element during for-each does not throw. |
127
+ | `TreeMap`, `SortedMap`, `NavigableMap` | Supported | Natural order or a `Comparator`: `put`, `get`, `getOrDefault`, `putIfAbsent`, `containsKey`, `containsValue`, `remove` (both forms), `replace`, `putAll`, `size`, `isEmpty`, `clear`, `firstKey`, `lastKey`, `floorKey`, `ceilingKey`, `lowerKey`, `higherKey` and their `…Entry` forms, `firstEntry`, `lastEntry`, `pollFirstEntry`, `pollLastEntry`, `comparator`, `keySet`, `navigableKeySet`, `descendingKeySet`, `values`, `entrySet`, `equals`, `hashCode`, `toString`. The live range views `headMap`, `tailMap`, `subMap` (with or without inclusive bounds) and `descendingMap`, as deep as wanted, with the JDK's `key out of range`, `fromKey out of range`, `toKey out of range` and `fromKey > toKey`. Constructors `()`, `(Comparator)`, `(Map)`, `(SortedMap)` (which keeps the comparator). The JDK's exceptions: `ClassCastException` for keys that are not Comparable or not mutually comparable, `NullPointerException` for a null key in natural order (`Cannot invoke "java.lang.Comparable.compareTo(Object)" because "k1" is null` when the map is empty), `NoSuchElementException` from `firstKey` of an empty map, `UnsupportedOperationException` from `setValue` on `firstEntry()`'s snapshot. Iterators fail fast as the JDK's do, and removing through one continues correctly. `comparator()` of a descending view is an engine limitation. |
128
+ | `TreeSet`, `SortedSet`, `NavigableSet` | Supported | `add`, `remove`, `contains`, `size`, `isEmpty`, `clear`, `first`, `last`, `floor`, `ceiling`, `lower`, `higher`, `pollFirst`, `pollLast`, `iterator`, `descendingIterator`, `comparator`, `headSet`, `tailSet`, `subSet` (live views, with or without inclusive bounds), `descendingSet`, `addAll`, `containsAll`, `toArray`, `equals`, `hashCode`, `toString`. Constructors `()`, `(Comparator)`, `(Collection)`, `(SortedSet)` (which keeps the comparator). Exceptions as for `TreeMap`. |
129
+ | `LinkedList` | Supported | A `List` and a `Deque`: every `ArrayList` method above, and `offer`, `offerFirst`, `offerLast`, `push`, `pop`, `poll`, `pollFirst`, `pollLast`, `peek`, `peekFirst`, `peekLast`, `element`, `remove()`, `removeFirstOccurrence`, `removeLastOccurrence`, `descendingIterator`. Null elements are allowed. Messages as the JDK's: `Index: 7, Size: 3` for an index out of range, `NoSuchElementException` from `getFirst`, `removeFirst`, `pop` or `element` on an empty list (`peek` and `poll` return null). Iteration fails fast as `ArrayList`'s does, and `sort` is not a structural change, so sorting during for-each does not throw. |
130
+ | `Stack` | Supported | `push`, `pop`, `peek` (`EmptyStackException` when empty), `empty`, `search`, every `List` method, and Vector's `elementAt`, `setElementAt`, `insertElementAt`, `removeElementAt`, `addElement`, `removeElement`, `removeAllElements`, `firstElement`, `lastElement`, `capacity`. As a Vector, its capacity starts at 10 and doubles, and shows in its messages: `Array index out of range: 5`, `Index -1 out of bounds for length 10`, `5 >= 2`, `5 > 2`. |
131
+ | `ArrayDeque`, `Deque`, `Queue` | Supported with limits | Both ends (`addFirst`/`addLast`, `offerFirst`/`offerLast`, `pollFirst`/`pollLast`, `peekFirst`/`peekLast`, `getFirst`/`getLast`, `removeFirst`/`removeLast`), as a stack (`push`, `pop`, `peek`) and a queue (`offer`, `poll`, `peek`, `element`, `remove()`, `add`). Also `contains`, `remove(Object)`, `removeFirstOccurrence`, `removeLastOccurrence`, `size`, `isEmpty`, `clear`, `iterator`, `descendingIterator`, `addAll`, `toString`. Constructors `()`, `(int)`, `(Collection)`. Null elements are an NPE, and an empty deque's `pop()` is `NoSuchElementException`, as in the JDK. Changing a deque while iterating over it is an engine limitation. |
132
+ | `PriorityQueue` | Supported with limits | Natural order or a `Comparator`: `offer`, `add`, `poll`, `peek`, `element`, `remove()`, `remove(Object)`, `contains`, `size`, `isEmpty`, `clear`, `iterator`, `addAll`, `toString`. Constructors `()`, `(int)`, `(Comparator)`, `(int, Comparator)`, `(Collection)` (a priority queue is copied with its comparator). The heap is laid out as the JDK lays it out, so it prints in the same order (`[1, 3, 2, 5, 9, 8, 7]`). Elements are `String`, `StringBuilder` or wrapper values; the JDK's `ClassCastException` for arrays and library objects is reproduced. In natural order, objects of the program's own classes are an engine limitation; give the queue a comparator for them. |
133
+ | `HashMap`, `Map`, `LinkedHashMap` | Supported with limits | `get`, `put`, `getOrDefault`, `putIfAbsent`, `containsKey`, `containsValue`, `remove(Object)`, `remove(key, value)`, `replace` (both forms), `putAll`, `size`, `isEmpty`, `clear`, `keySet`, `values`, `entrySet`, `equals`, `hashCode`, `toString`. Constructors `()`, `(int)`, `(Map)`. **Iteration order is the JDK's:** the table is laid out as JDK 25 lays it out (power-of-two buckets, the spread hash, chains appended in order, doubling at three quarters full with each chain split in order, a bucket of 9 or more colliding keys turned into a red-black tree whose root comes first), so a map prints and iterates as on the JDK, `{over=1, mat=1, a=1, quick=1, …}`. `LinkedHashMap` iterates in insertion order. The views write through: `keySet().remove`, `values().remove`, an iterator's `remove`, and `Map.Entry.setValue`. Their iterators fail fast exactly as the JDK's: removing the last key during for-each does not throw, adding one does. Lookups are exact: `Integer` 1 and `Long` 1 are different keys, and so are `0.0` and `-0.0`. Null keys and values work, and a key's declared `hashCode()` runs where the JDK runs it. Where the JDK's order cannot be known, iterating is an engine limitation (below). `merge`, `compute…`, `forEach` and the other lambda-taking methods, and access-ordered `LinkedHashMap`, are unsupported. |
134
+ | `Map.Entry` | Supported | `getKey`, `getValue`, `setValue`, `equals`, `hashCode` (key's hash xor value's), `toString` (`k=v`). Named `Map.Entry`, or `Entry` after `import java.util.Map.Entry;`. |
135
+ | `HashSet`, `Set`, `LinkedHashSet` | Supported with limits | `add`, `contains`, `remove`, `size`, `isEmpty`, `clear`, `addAll`, `containsAll`, `equals`, `hashCode`, `iterator`, `toArray`, `toString`. Constructors `()`, `(int)`, `(Collection)`, sized as the JDK sizes them, so their order is the JDK's too. A `HashSet` is a `HashMap` of its elements, as in the JDK, and iterates in the same order; `LinkedHashSet` in insertion order. Membership is exact, and a `Set<List<Integer>>` compares lists by content. |
136
+ | `List.of`, `Set.of`, `Map.of`, `Map.ofEntries`, `Map.entry`, `copyOf` | Supported with limits | Immutable, as the JDK's: changing one is `UnsupportedOperationException`, null elements are `NullPointerException` (with the JDK's message for each size class: `Cannot invoke "Object.hashCode()" because "pk" is null` from a `Map.of` of several entries), `get` out of range is `Index: 1 Size: 1` or `Index 5 out of bounds for length 3`, duplicates are `IllegalArgumentException: duplicate element: 1` / `duplicate key: k`. `List.of` iterates in order. The JDK randomizes the order of a `Set.of` or `Map.of` on every run, so iterating or printing one of more than one element is an engine limitation; lookups, `size` and `equals` are exact. |
137
+ | `Arrays.asList` | Supported | A fixed-size list over the array itself: `set` and the array see each other's changes, `add` and `remove` are `UnsupportedOperationException`, `Collections.sort` sorts the array. `Arrays.asList(intArray)` is a `List<int[]>` of one element, as in Java. |
138
+ | `Collections` | Supported with limits | `sort`, `reverse`, `swap`, `max`, `min` (natural order or a `Comparator`), `frequency`, `addAll`, `fill`, `shuffle` (with a seeded `Random`, the JDK's permutation), `nCopies`, `emptyList`, `emptySet`, `emptyMap`, `singletonList`, `singleton`, `singletonMap`, and the `unmodifiableList`, `Set`, `Map` and `Collection` views, with the JDK's exceptions (`List length = -1`, `Index: 1, Size: 1`, `NoSuchElementException` from `max` of an empty collection). `reverseOrder`, `binarySearch`, `rotate` and the rest are unsupported. |
139
+ | `toArray()`, `toArray(T[])` | Supported | On every collection: a new `Object[]`, or the given array when the elements fit (the next slot set to null), else a new array of its type; an element it cannot hold is the JDK's `ArrayStoreException: arraycopy: element type mismatch: …`. |
140
+ | `Comparator`, `Collections.sort` | Supported | `compare`; `reversed`, `thenComparing` (a comparator, a key, or both), `thenComparingInt`/`Long`/`Double`; `Comparator.comparing` (with or without a key comparator), `comparingInt`/`Long`/`Double`, `naturalOrder`, `reverseOrder`, `nullsFirst`, `nullsLast`; `Map.Entry.comparingByKey`/`comparingByValue`; `Collections.reverseOrder`. They compare as their documentation specifies, calling the program's lambdas and methods as Java code, with the JDK's NPE messages (`Cannot invoke "java.lang.Comparable.compareTo(Object)" because the return value of "java.util.function.Function.apply(Object)" is null`). A comparator sort is TimSort, written from its published description with Java's parameters, so even a comparator that breaks its contract (`(a, b) -> a - b` overflowing) orders elements as the JDK does, is called as many times, and fails with the same `IllegalArgumentException: Comparison method violates its general contract!` where the JDK's does. An exception in a comparator shows the lambda's frame. |
141
+ | Higher-order collection methods | Supported | `forEach` (every collection and map, and iterators' `forEachRemaining`), `removeIf`, `List.replaceAll`, `Map.replaceAll`, `computeIfAbsent`, `computeIfPresent`, `compute`, `merge`, `toArray(String[]::new)`, and the functions' `andThen`, `compose`, `identity`, `and`, `or`, `negate`, `Predicate.not`, `Predicate.isEqual`, `BinaryOperator.minBy`/`maxBy`. Each follows its class's JDK behavior: `HashMap.merge`, `compute` and `computeIfAbsent` add a new key at the front of its bucket (unlike `put`), so a map built with them prints in the JDK's order; a function that changes the map is a `ConcurrentModificationException`; `HashMap.forEach` finishes before reporting a change, `ArrayList.forEach` stops at it, `TreeMap.forEach` reports it at once; `ArrayList.removeIf` tests every element before removing any. Immutable collections reject them with `UnsupportedOperationException`. |
142
+ | Streams (`java.util.stream`) | Supported with limits | `Stream`, `IntStream`, `LongStream`, `DoubleStream`, from `collection.stream()`, `Arrays.stream` (whole or a range), `Stream.of`, `IntStream.range`/`rangeClosed`/`of`, `iterate`, `generate`, `concat`, `empty`, `String.chars()`. Intermediate: `filter`, `map`, `mapToInt`/`Long`/`Double`/`Obj`, `boxed`, `asLongStream`/`asDoubleStream`, `flatMap`, `distinct`, `sorted` (natural or a `Comparator`), `peek`, `limit`, `skip`, `takeWhile`, `dropWhile`. Terminal: `forEach`, `collect`, `toList` (unmodifiable, nulls allowed), `toArray`, `reduce`, `count`, `sum`, `min`, `max`, `average`, `summaryStatistics`, `anyMatch`/`allMatch`/`noneMatch`, `findFirst`/`findAny`. A pipeline runs as the JDK's does, which a program can observe through side effects: nothing happens before the terminal operation; each element goes through every stage before the next (`filter 1`, `filter 2`, `map 2`, …); `sorted` takes every element, then passes them on; `limit`, `findFirst` and the matches stop the source early; and `count()` of a pipeline whose size is known without running it (no `filter`, `distinct` or `flatMap`) runs nothing, so a `peek` before it prints nothing. A stream used twice is the JDK's `IllegalStateException: stream has already been operated upon or closed`. `DoubleStream.sum` and `average` use the JDK's compensated summation. Parallel streams, `iterator()`, `mapMulti`, the three-argument `collect` and `reduce`, and `LongStream`/`DoubleStream`'s `iterate`/`generate`/`concat` are unsupported. |
143
+ | `Collectors` | Supported with limits | `toList`, `toUnmodifiableList`, `toSet`, `toCollection`, `toMap` (two, three or four arguments; a duplicate key is the JDK's `IllegalStateException: Duplicate key a (attempted merging values 1 and 1)`), `groupingBy` (one, two or three arguments), `partitioningBy` (`{false=..., true=...}`), `counting` (a `Long`), `summingInt`/`Long`/`Double`, `averagingInt`/`Long`/`Double`, `summarizingInt`/`Long`/`Double`, `joining` (with a delimiter, prefix and suffix), `mapping`, `filtering`, `flatMapping`, `collectingAndThen`, `reducing`, `minBy`, `maxBy`. Maps are filled as the JDK fills them (`groupingBy` through `computeIfAbsent`, so a `HashMap` prints in the JDK's order). `teeing`, `toUnmodifiableSet`/`Map` and the concurrent collectors are unsupported. Type arguments are inferred as javac infers them in the common forms: `collect(Collectors.toList())`, `groupingBy(w -> w.charAt(0), TreeMap::new, Collectors.counting())`, `collectingAndThen(Collectors.toList(), List::size)`. |
144
+ | `Optional`, `OptionalInt`, `OptionalLong`, `OptionalDouble`, `IntSummaryStatistics` (and `Long`, `Double`) | Supported | `of`, `ofNullable`, `empty`, `get`/`getAsInt`/…, `isPresent`, `isEmpty`, `orElse`, `orElseGet`, `orElseThrow` (with or without a supplier), `ifPresent`, `ifPresentOrElse`, `map`, `flatMap`, `filter`, `or`, `stream`; printed as `Optional[3]`, `Optional.empty`, `OptionalDouble[1.5]`; `NoSuchElementException: No value present`. The statistics' `getCount`, `getSum`, `getMin`, `getMax`, `getAverage`, `accept`, and `IntSummaryStatistics{count=3, sum=80, min=20, average=26.666667, max=30}`. |
145
+ | `EnumMap`, `EnumSet` | Supported | An enum's constants in ordinal order. `EnumMap(Class)`, `(EnumMap)`, `(Map)` (an empty non-EnumMap is `IllegalArgumentException: Specified map is empty`), with every `Map` method; a null key is the JDK's NPE on `put` and simply absent on `get`, `containsKey` and `remove`. `EnumSet.noneOf`, `allOf`, `of` (one to five constants, or varargs), `range` (`C > A` when reversed), `complementOf`, `copyOf` (`Collection is empty`), `clone`, with every `Set` method plus `removeAll` and `retainAll`; its iterator walks a snapshot, so removing while iterating never fails, as on the JDK. `getClass()` is `java.util.EnumMap` and `java.util.RegularEnumSet` (`JumboEnumSet` above 64 constants). |
146
+ | `java.math.BigInteger` | Supported | `ZERO`, `ONE`, `TWO`, `TEN`, `valueOf` (sharing -16..16 as the JDK does, so `valueOf(1) == ONE`), `new BigInteger(String[, radix])` with the JDK's messages (`Zero length BigInteger`, `For input string: "x10"` naming the failing digit group, `Radix out of range`, `Illegal embedded sign character`); `add`, `subtract`, `multiply`, `divide`, `remainder`, `mod`, `divideAndRemainder`, `pow`, `modPow`, `modInverse`, `gcd`, `abs`, `negate`, `signum`, `sqrt`, `min`, `max`, `compareTo`, `equals`, `hashCode` (the JDK's), `toString` (any radix), the `…Value` and `…ValueExact` conversions, bit operations (`shiftLeft`, `and`, `testBit`, `bitLength`, `bitCount`, …), `isProbablePrime`, `nextProbablePrime`, with the JDK's `ArithmeticException` messages. `%d`, `%x` and `%o` format it (signed: `-ff`). Comparable, so it sorts and keys TreeMaps; content-equal in HashMaps. Non-ASCII digits are an engine limitation; `probablePrime` and `toByteArray` are unsupported. |
147
+ | `java.math.BigDecimal`, `RoundingMode`, `MathContext` | Supported | A BigInteger unscaled value and a scale, as the JDK's: `new BigDecimal(String)` (with its messages), `(double)` (the double's exact value: `0.1000000000000000055511151231257827021181583404541015625`), `(int)`, `(long)`, `(BigInteger[, scale])`, `valueOf(double)` (via `Double.toString`), `valueOf(long[, scale])` (sharing 0..10 as the JDK does); `add`, `subtract`, `multiply` (scale rules as documented), `divide` exact (the preferred scale, or the smallest that holds the quotient: `5 / 0.25` is `2E+1`; `Non-terminating decimal expansion; no exact representable decimal result.`), with a scale and `RoundingMode`, or a `MathContext`; `divideToIntegralValue`, `remainder`, `setScale` (`Rounding necessary`), `round`, `sqrt`, `pow`, `movePointLeft`/`Right`, `scaleByPowerOfTen`, `stripTrailingZeros`, `precision`, `unscaledValue`, `compareTo` (by value) and `equals` (value and scale: `1.10` is not `1.1`), `hashCode` (the JDK's), `toString` (scientific when the JDK's is: `1E+2`, `1.234E-7`), `toPlainString`, the conversions. All eight `RoundingMode`s (`values()`, `valueOf`, `name`, `ordinal`) and `MathContext` (`DECIMAL32`, `DECIMAL64`, `DECIMAL128`, `UNLIMITED`, its constructors). `%f`, `%e` and `%g` format a BigDecimal from its exact digits. Scanner's `nextBigInteger` and `nextBigDecimal` read them. The `MathContext` forms of `add` and the other arithmetic, `ulp` and `toEngineeringString` are unsupported. |
148
+ | `Iterator`, `Iterable`, `Collection` | Supported | `hasNext`, `next`, `remove`, with the JDK's `NoSuchElementException`, `IllegalStateException` and `ConcurrentModificationException`. |
149
+ | `StringBuilder` | Supported | `append` (every supported type, `char[]`, and objects through their `toString()`), `insert`, `delete`, `deleteCharAt`, `replace`, `reverse` (surrogate pairs stay in order), `charAt`, `setCharAt`, `setLength`, `length`, `isEmpty`, `indexOf`, `lastIndexOf`, `substring`, `compareTo`, `equals` and `hashCode` (identity), `toString`. Constructors `()`, `(int)`, `(String)`. Index errors with the JDK's messages: `Index 10 out of bounds for length 3`, `Range [4, 3) out of bounds for length 3`, `String index out of range: -1`. |
150
+ | `Number`, `Integer`, `Long`, `Double`, `Float`, `Byte`, `Short`, `Boolean` methods | Supported with limits | `Number` is the numeric wrappers' superclass, with `byteValue`, `shortValue`, `intValue`, `longValue`, `floatValue` and `doubleValue` (`List<Number>`, `T extends Number`, `List<? extends Number>`; `new Number()` is javac's `Number is abstract; cannot be instantiated`). Statics: `parseInt` and `parseLong` (with a radix), `parseDouble`, `parseBoolean`, `valueOf`, `toString`, `compare`, `max`, `min`, `sum`, `signum`, `bitCount`, `toBinaryString`, `toHexString`, `toOctalString`, `numberOfLeadingZeros`, `numberOfTrailingZeros`, `highestOneBit`, `reverse`, `hashCode`, `isNaN`, `isInfinite`, `isFinite`, `logicalAnd`, `logicalOr`, `logicalXor`. On boxed values: `intValue`, `longValue`, `doubleValue`, `charValue`, `booleanValue`, `isNaN`, `isInfinite`, `compareTo`, `equals`, `hashCode`, `toString`. The JDK's `NumberFormatException` messages: `For input string: "12a"`, `… under radix 16`, `Cannot parse null string`, `empty String`. `Float`: `parseFloat` (rounded once, never through double), `floatToIntBits`, `floatToRawIntBits`, `intBitsToFloat`, and Double's other statics; `Float.valueOf` never caches, as on the JDK. `Byte` and `Short`: `parseByte`/`parseShort` (with a radix; `Value out of range. Value:"128" Radix:10`), `toUnsignedInt`, `toUnsignedLong`, and the caches (every `Byte`, `Short` in -128..127). `parseDouble` and `parseFloat` read hexadecimal strings, and report `multiple points` as the JDK does. |
151
+ | `Character` methods | Supported with limits | `isLetter`, `isDigit`, `isLetterOrDigit`, `isAlphabetic`, `isUpperCase`, `isLowerCase`, `isWhitespace`, `isSpaceChar`, `toUpperCase`, `toLowerCase` (the `char` and `int` forms), `getNumericValue`, `digit`, `forDigit`, `valueOf`, `toString`, `compare`, `hashCode`. Exact for Latin-1 (U+0000 to U+00FF), whose answers were recorded from JDK 25: `é` is a letter, `ÿ` upper-cases to `Ÿ`, and `ß` stays `ß`. Other characters are an engine limitation (SPEC.md §4.2.2). |
152
+ | `Arrays` | Supported with limits | `toString`, `deepToString`, `sort` (whole or a range, for every primitive array but `boolean[]`, and object arrays; objects in natural order or by a `Comparator`, stably), `fill` (whole or a range), `equals`, `hashCode`, `binarySearch`, and `copyOf` and `copyOfRange` (an object array's copy keeps its class: a `String[]` stays a `String[]`). The JDK's exceptions: `fromIndex(2) > toIndex(1)`, `Array index out of range: 4`, `ArrayStoreException: java.lang.Integer`, and `Cannot read the array length because "a" is null`. `asList` is below. `stream` is below. Sorting a primitive array with a comparator is javac's `no suitable method` error. Sorting an object array that contains null is an engine limitation. |
153
+ | Other `PrintStream` methods, `System.in`'s own methods, the `System`, `Math` and `String` methods not listed here, array methods; other java.util classes; the library methods not listed here | Unsupported | A real method of a supported class is reported as `the List method parallelStream() is not supported in this version`, not as `cannot find symbol`. An overload outside the subset is chosen as javac would choose it, then reported (`the constructor HashSet(int, float) is not supported`). |
154
+
155
+ ## Practice mode
156
+
157
+ Instead of running `main`, a host can call one method with test cases and get a result per case (ADR 0005). code-playpad exposes it as the `practice` option.
158
+
159
+ | Feature | Status | Notes |
160
+ | --- | --- | --- |
161
+ | Calling a method with cases | Supported | By name, or by name and parameter types (`params: ["int[]", "int"]`) when it is overloaded; static or instance (on a fresh instance from the no-argument constructor; not in an inner class). The program needs no `main`. Each case runs in a fresh runtime, so static fields and identity start over. At most 500 cases. |
162
+ | Values | Supported with limits | JSON: `int` (number), `long` (decimal string), `char` (one-character string), `boolean`, `double` (number, or `"NaN"`, `"Infinity"`, `"-Infinity"`), `String`, wrapper types, `null`, arrays of these (nested), `List`/`ArrayList`, and linked-list and tree nodes (values in order; level order with `null` gaps), recognized from their fields or described in `nodes`. Maps, sets and `Object` are not supported yet: the spec is rejected with a message. |
163
+ | Comparison | Supported with limits | Ordered deep equality of the encoded values, or within a `tolerance` for doubles. A `void` method is checked through an argument after the call (`compare: { kind: "argument", index }`). Unordered comparison and stateful multi-call exercises are not supported yet. |
164
+ | Case results | Supported | `passed`, `failed` (with expected and actual), `completed` (no expected value), `runtime-error` (with the stack trace a program would print), `resource-limit`, `engine-limitation`, `invalid-case` (the JSON does not fit the parameters), `not-run` (with the reason), plus what the case printed. A cyclic or oversized result is `ResultEncodingError`. |
165
+
166
+ ## Compile-time checks
167
+
168
+ These all use javac's wording and caret positions, as evidenced by `tests/jdk-cases`:
169
+
170
+ - **Name and type errors:**
171
+ - cannot find symbol (variable, method, class), with `symbol:`/`location:` lines
172
+ - `incompatible types` (including `possible lossy conversion from int to char`)
173
+ - bad operand types, and `incomparable types`
174
+ - `X cannot be dereferenced`
175
+ - `array required, but int found`
176
+ - `illegal initializer for int`
177
+ - `cannot assign a value to final variable length`
178
+ - `already defined` for variables, methods, constructors and member classes; `duplicate class`
179
+ - `non-static … cannot be referenced from a static context`
180
+ - `… has private access in …`
181
+ - `invalid method declaration; return type required`, `modifier static not allowed here`, `explicit constructor invocation may only appear within a constructor body`
182
+ - **Method and constructor calls:**
183
+ - `method f in class Main cannot be applied to given types;` with `required`/`found`/`reason` (and the same for constructors)
184
+ - `no suitable method found for …` / `no suitable constructor found for …`, with every candidate and why it does not apply
185
+ - `reference to f is ambiguous`
186
+ - **Definite assignment (JLS 16):** includes `&&`/`||`/`!`/`?:`, constant conditions, `for` loops, and `break`; definite unassignment for blank `final` fields in constructors, with javac's second pass over loops.
187
+ - **Reachability (JLS 14.22):** after `return`/`break`/`continue`, after loops that cannot exit, and for a `while (false)` or `for (; false; )` body. `if (false)` is allowed.
188
+ - **`missing return statement`**
189
+ - **Error order:** one top-level class at a time, in source order: its attribution errors (nested classes where they are declared), then reachability, then definite assignment, with nested classes first. **Once any error has been reported, flow analysis does not run**, exactly as in javac, so a type error hides a missing return in the same file, and so does an error in an earlier class.
190
+ - **Syntax, lexical, and number-literal errors:** as in 0.1.0.
191
+
192
+ **Output format:** the same as `java Main.java`. **Warnings:** none (JDK 25 source-file mode prints none for these programs either).
193
+
194
+ ## Exceptions
195
+
196
+ | Feature | Status | Notes |
197
+ | --- | --- | --- |
198
+ | The JDK's exception classes | Supported with limits | `Throwable`, `Exception`, `Error`, `RuntimeException`, and in `java.lang`: `ArithmeticException`, `ArrayIndexOutOfBoundsException`, `ArrayStoreException`, `ClassCastException`, `CloneNotSupportedException`, `IllegalArgumentException`, `IllegalStateException`, `IndexOutOfBoundsException`, `InterruptedException`, `NegativeArraySizeException`, `NullPointerException`, `NumberFormatException`, `ReflectiveOperationException`, `ClassNotFoundException`, `StringIndexOutOfBoundsException`, `UnsupportedOperationException`, `AssertionError`, `LinkageError`, `ExceptionInInitializerError`, `NoClassDefFoundError`, `VirtualMachineError`, `StackOverflowError`, `OutOfMemoryError`; in `java.util`: `NoSuchElementException`, `InputMismatchException`, `ConcurrentModificationException`, `EmptyStackException`, and the `IllegalFormatException` family (catchable, not constructible); `java.util.regex.PatternSyntaxException` (catchable); in `java.io` (imported): `IOException`, `FileNotFoundException`, `EOFException`, `UncheckedIOException` (whose cause may be any Throwable here). Their public constructors: `()`, `(String)`, and where the JDK has them `(String, Throwable)`, `(Throwable)` (the message is the cause's `toString()`), `(int)` for the index exceptions (`Index out of range: 5`), `AssertionError(Object)`. What the engine and the library throw are these classes, so `catch` matches them. Other constructors, such as the protected `(String, Throwable, boolean, boolean)`, are unsupported. |
199
+ | The program's exception classes | Supported | `class InsufficientFunds extends Exception`, with fields, constructors calling `super(message)` or `super(message, cause)`, and overrides of `getMessage()`, `toString()` or `fillInStackTrace()`. Anonymous exception classes are unsupported. |
200
+ | `Throwable` methods | Supported with limits | `getMessage`, `getLocalizedMessage`, `getCause`, `initCause` (`Can't overwrite cause with …`, `Self-causation not permitted`), `toString` (`Main$InsufficientFunds: short by 14`), `printStackTrace()` to `System.err`, `addSuppressed` (`Self-suppression not permitted`, `Cannot suppress a null exception.`), `getSuppressed`, `fillInStackTrace`, and `getClass().getName()` / `getSimpleName()`. A trace is recorded when the exception is made, not where it is thrown, as in Java. `getStackTrace`, `setStackTrace` and `printStackTrace(PrintStream)` are unsupported. |
201
+
202
+ ## Runtime behavior
203
+
204
+ - **Uncaught exceptions:** printed exactly as the JDK prints them, with one frame per active method call, innermost first, each at the line of its current statement, then each `Suppressed:` exception and `Caused by:` with its frames. The exception's own `toString()` runs as a Java call; if it throws, the JVM's `Exception: … thrown from the UncaughtExceptionHandler in thread "main"` is printed instead.
205
+ - `ArithmeticException: / by zero`
206
+ - `ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3`
207
+ - `NegativeArraySizeException: -2`
208
+ - `StringIndexOutOfBoundsException: Index 5 out of bounds for length 3`
209
+ - `StackOverflowError`
210
+ - **NullPointerException messages** match the JDK's helpful messages:
211
+ - Examples: `Cannot load from int array because "<local1>" is null`, `Cannot invoke "String.length()" because "<local2>[<local1>]" is null`, `… because the return value of "Main.find(String[], char)" is null`.
212
+ - Local variables are named by JVM slot, as the JDK names them for code compiled without debug information (source-file mode). The engine allocates slots the way javac does, reusing a slot once its variable's block has ended.
213
+ - **Recursion:** the default depth is 50,000 calls; beyond that, a Java `StackOverflowError`. JDK 25's own limit varies from run to run: 45,810 to 94,701 frames were measured for simple methods.
214
+ - **Initializer failures:** an exception in a static initializer becomes `ExceptionInInitializerError` at the first use of the class, with `Caused by:` and frames down to `Table.<clinit>` (an `Error` such as `StackOverflowError` passes through unwrapped). The class is then erroneous: each later use throws `NoClassDefFoundError: Could not initialize class Main$Config`, caused by `ExceptionInInitializerError: Exception java.lang.ArithmeticException: / by zero [in thread "main"]` with the original frames, as JDK 25 reports it. One in a constructor or instance field initializer is reported with `Counter.<init>` frames.
215
+ - **Field and object NPE messages:** as the JDK words them: `Cannot read field "value" because "<local2>" is null`, `Cannot assign field "next" …`, `Cannot invoke "Node.show(int)" …`, `Cannot invoke "Object.hashCode()" …`, and sources such as `"this.data"`, `"Main.data"`, `"<parameter1>.next"`, `"this.this$0.data"`, `"Main.make().next"`. An inner class constructor's parameters are numbered after its hidden enclosing-instance parameter, as on the JVM (`<parameter3>`).
216
+ - **`toString()` calls** from `println` and string concatenation run as real Java calls: an exception inside one shows its frame.
217
+ - **Library exceptions** carry the JDK's messages: `IndexOutOfBoundsException`, `NoSuchElementException`, `ConcurrentModificationException`, `IllegalArgumentException`, `ClassCastException`, `NumberFormatException`, `ArrayStoreException`, and the helpful NPEs thrown inside the JDK (`Cannot invoke "java.util.Collection.toArray()" because "c" is null`). The stack shows the program's frames (see *Known divergences*).
218
+ - **Callbacks:** the `toString()` and `hashCode()` methods that the library calls run as Java calls, in the same order and number as on the JDK, so their output and exceptions appear as they would there.
219
+ - **Fresh state:** each run starts from fresh state; nothing (intern pool, arrays, identity hashes, static fields) survives between runs.
220
+
221
+ ## Known divergences from the JDK
222
+
223
+ | Case | JDK 25 | Engine | How the tests compare it |
224
+ | --- | --- | --- | --- |
225
+ | Exceptions thrown inside the JDK (`charAt` out of range, `println` of a null `char[]`, any library method), inside a `toString()` called by `println`, `+` or a collection, or during class initialization or instance creation; and every trace `printStackTrace()` prints | The program's frames plus the JDK's own frames (`at java.base/…` such as `String.valueOf`, the source launcher's five frames below `main`, `at jdk.compiler/…`) | Same messages and program frames, without the JDK's frames. `... N more` counts the launcher's frames, so it is the JDK's number | Identical once the JDK's frames are removed |
226
+ | `no suitable method found for sort(...)` with a generic `Arrays.sort` candidate | javac prints the generic overloads as `Arrays.<T#1>sort(…)` with inference details and a `where` clause | The overloads the engine has, with substituted types | Each error's header, source line and caret identical |
227
+ | `StackOverflowError` trace length | Capped at 1024 frames; 1019 were printed in the recorded case | 1024 frames | First lines identical |
228
+ | A lexical error (`int #x`, unclosed comment, unclosed text block) | Follow-on syntax errors after javac's error recovery | The lexical error only | First diagnostic identical |
229
+ | Several syntax errors in one file | javac may report several | The engine stops at the first | (by design, ADR 0001) |
230
+ | Printing an array or an object without `toString()` (`[I@5fdba6f9`, `Node@6dde5c8c`), or `hashCode()` | Random identity hash | Deterministic per-run hash with the same format | Format checked by unit tests |
231
+ | `Math.sin`, `exp`, `pow`, `log` and the other transcendental functions | Results of the platform's math library | JavaScript's; about 3% of probed values differed in the last digit (accepted by the owner, 2026-10-18) | The recorded cases print them with `printf("%.12f")`; unit tests allow a few ulps. Java permits this: `Math`, unlike `StrictMath`, need not be reproducible across platforms |
232
+ | Unseeded `new Random()`, `Math.random()`, `System.currentTimeMillis()`, `nanoTime()`, `identityHashCode` | Differ on every run | Differ on every run (identity hashes are per-run, as above) | Ranges checked by unit tests |
233
+ | Passing a `String[]` to an `Object...` parameter (`String.format("%s", strings)`) | javac's `non-varargs call of varargs method with inexact argument type` warning | The same behavior, without the warning | Engine-only test |
234
+ | A regex that backtracks exponentially (`(a+)+b` on a long run of `a`) | Runs for a very long time | Also runs for a very long time; JavaScript's regex engine is not interrupted by the instruction limit | Stopping terminates the worker (SPEC.md §6.1) |
235
+ | A `ClassCastException` about the program's classes | Names the source launcher's class loader with its identity hash (`MemoryClassLoader @78186a70`), different on every run | The same message with a fixed hash | Recorded cases mask the hash (`loader-hash`) |
236
+ | `Scanner.nextDouble()` of `3.5` | Depends on the JDK's default locale: `3.5` under English (the reference JDK's), not a number under German, where the decimal separator is `,` | The English locale's rules, always: `.` is the decimal separator and `,` groups thousands (owner decision, 2026-10-18: online judges and the reference JDK run under English, and the result does not depend on the machine) | Recorded under the reference JDK's locale (`sc-*`) |
237
+ | Requesting an array of about 2³¹ elements | `OutOfMemoryError: Requested array size exceeds VM limit` | `resource-limit` (array budget) | Engine-only test |
238
+
239
+ ## Engine limitations (reported as `engine-limitation`)
240
+
241
+ Where reproducing the JDK would mean guessing, the engine stops instead: `Stopped: … (limitation of this in-browser Java engine).`, with status `engine-limitation` and exit code 1. Output printed before it is kept.
242
+
243
+ | The program | Why the engine stops |
244
+ | --- | --- |
245
+ | Iterates over or prints a `HashMap` or `HashSet` of more than one element whose keys are hashed by identity (objects of a class without `hashCode()`, enums, arrays) | The JDK's identity hash codes, and so its order, differ on every run. `LinkedHashMap`/`LinkedHashSet` iterate in insertion order and need no hash codes |
246
+ | Iterates over or prints a `Set.of`, `Set.copyOf`, `Map.of` or `Map.copyOf` of more than one element, or a hash table filled from one | The JDK randomizes their order on every run |
247
+ | Iterates over a `HashMap` or `HashSet` after removing keys from a bucket of 9 or more colliding keys, or where such a bucket holds many keys with equal hash codes | The JDK rebalances the bucket's tree (or orders equal hashes by identity); that part of its order is not reproduced |
248
+ | Changes an `ArrayDeque` while iterating over it | The JDK's result depends on its internal array layout |
249
+ | Orders objects of its own classes (`PriorityQueue`, `Arrays.sort`) | The JDK's `ClassCastException` names the class loader with an identity hash |
250
+ | Sorts objects in natural order when one is null, or makes a priority queue whose natural-order comparisons meet a null element on the left | The JDK's NPE message names a local variable of its sorting code |
251
+ | Prints a lambda | The JDK prints its generated class and address (`Main$$Lambda/0x…@…`) |
252
+ | Calls `Iterator.remove()` on a PriorityQueue's iterator | The JDK reorders the heap in a way that is not reproduced |
253
+ | Classifies or case-maps a character outside Latin-1, or parses digits outside Latin-1 | The Unicode tables are not bundled (SPEC.md §4.2.2) |
254
+ | Uses a regex construct JavaScript's engine has no equivalent for: possessive quantifiers (`a++`), atomic groups (`(?>…)`), class intersections (`[a-z&&[^b]]`) and nested classes, inline flags other than a leading `(?i)`/`(?s)`, the `m`, `x`, `u`, `U`, `d` and `c` flags, `\G`, Unicode categories (`\p{L}`), negated classes inside a class (`[\S ]`), or supplementary characters in the pattern | Translating them would change what matches |
255
+ | Matches case-insensitively against non-ASCII text | Java's and JavaScript's case folding differ outside ASCII |
256
+ | Formats a date or time (`%t`) or hexadecimal floating point (`%a`) | Not implemented |
257
+ | Reads `System.in` through two readers: two `Scanner`s or `BufferedReader`s, one of each, or `IO.readln` together with one | On the JDK the first reader buffers the input, so the second sees part of it or none, depending on buffer sizes; make one Scanner and pass it around |
258
+ | Reads a number written with non-ASCII digits with a Scanner | Not implemented |
259
+ | Prints a `Scanner` | The JDK prints its locale's number symbols |
260
+
261
+ ## Limits (engine-specific; reported as `resource-limit`, never as Java exceptions)
262
+
263
+ | Limit | Default | Notes |
264
+ | --- | --- | --- |
265
+ | Instructions | 200,000,000 | A step is one bytecode instruction, some of which do the work of several (ADR 0019); 200M steps take roughly 0.6–1.5 s on the development Mac (a sieve of 5,000,000 numbers: 128M steps, 424 ms; fib(30): 95 ms). A library call into the program (a comparator, `merge`'s function) costs about 0.1–0.2 µs (ADR 0020). Allocation, concatenation, and output are charged extra. Deterministic. |
266
+ | Array elements | 16,000,000 per run | Checked before allocating. Collection entries count too. |
267
+ | Output | 1,000,000 characters | Truncated exactly at the limit. |
268
+ | String length | 10,000,000 characters | A `StringBuilder` too. |
269
+ | Call depth | 50,000 | Exceeding it is a Java `StackOverflowError`, not a resource limit. |
270
+ | Source | 500,000 characters per file, 32 files | |
271
+ | Nesting | 200 levels of statements and parentheses; expressions 1,000 deep | |
272
+ | Wall clock | none in the engine | Stop terminates the worker (SPEC.md §6.1). |