Java
language="java" compiles and runs a documented subset of
Java 25 in the reader's browser. There is no JVM and no server: an engine
written for code-playpad type-checks the program, compiles it, and
interprets it in a Web Worker. It is one ~39KB (gzipped) chunk, and pages
without a Java widget never download it.
Hello, compact source file
Java 25 lets a small program be just methods and fields: no
class declaration, and a main that is neither
public nor static. IO.println
prints anything. Fields keep their values across method calls, because
the launcher creates one instance and calls main on it.
int visits = 0;
void main() {
greet("Ada");
greet("Grace");
IO.println("greeted " + visits + " people");
}
void greet(String name) {
visits++;
IO.println("Hello, " + name + "!");
}
Or a classic class
The familiar form works too: a class with
public static void main(String[] args), static methods,
and arrays. Integer arithmetic is real 32-bit Java arithmetic, so
(low + high) >>> 1 does exactly what it does on a
JVM.
public class Main {
// Returns the index of target in sorted, or -1 when it is absent.
static int binarySearch(int[] sorted, int target) {
int low = 0;
int high = sorted.length - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
if (sorted[mid] == target) return mid;
if (sorted[mid] < target) low = mid + 1;
else high = mid - 1;
}
return -1;
}
public static void main(String[] args) {
int[] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
System.out.println("index of 13: " + binarySearch(primes, 13));
System.out.println("index of 4: " + binarySearch(primes, 4));
}
}
Methods, recursion and overloading
Calls are resolved the way javac resolves them, overloads
included: describe('x') picks the char version
and describe('x' + 1) the int one. Recursion is
real, and so is overflow: 13! does not fit in an
int.
static int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
static String describe(int x) { return "int " + x; }
static String describe(char c) { return "char " + c; }
void main() {
for (int n = 10; n <= 13; n++) {
IO.println(n + "! = " + factorial(n));
}
IO.println(describe('x'));
IO.println(describe('x' + 1));
}
Strings, characters and arrays
A char is a number you can count with
(c - 'a'), and Strings index by UTF-16 code unit, as in
Java. == compares references, so use
equals for content.
void main() {
String text = "hello world";
int[] counts = new int[26];
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c >= 'a' && c <= 'z') counts[c - 'a']++;
}
for (char c = 'a'; c <= 'z'; c++) {
if (counts[c - 'a'] > 1) IO.println(c + " appears " + counts[c - 'a'] + " times");
}
String built = "hel";
built += "lo";
IO.println(built == "hello"); // false: a different object
IO.println(built.equals("hello")); // true: same characters
}
Numbers and switch
long and double behave exactly as on a JVM,
down to how a double prints (0.30000000000000004) and how
an int overflows. A switch can be a
statement or, as here, an expression with several labels per case;
arrays can have more dimensions, and enhanced for walks
them.
void main() {
long population = 8_100_000_000L;
double growth = 0.0088;
for (int year = 2026; year <= 2028; year++) {
population += (long) (population * growth);
IO.println(year + ": " + population);
}
IO.println(0.1 + 0.2);
IO.println(Integer.MAX_VALUE + 1);
IO.println(Long.MAX_VALUE / 7 + " " + 22.0 / 7);
int[][] scores = {{90, 72}, {65, 88}, {100, 41}};
for (int[] pair : scores) {
int best = Math.max(pair[0], pair[1]);
String grade = switch (best / 10) {
case 10, 9 -> "A";
case 8 -> "B";
case 7 -> "C";
default -> "below C";
};
IO.println(best + " -> " + grade);
}
}
Objects and classes
Declare classes with fields, constructors and methods, create them with
new, and link them together. A toString()
you write is what IO.println and + use. In a
compact source file, classes like these are members of the file's
implicit class, so they can also use its fields.
void main() {
Stack stack = new Stack();
for (int n = 1; n <= 3; n++) stack.push(n * n);
IO.println(stack);
IO.println("popped " + stack.pop() + ", now " + stack);
IO.println(stack.isEmpty() ? "empty" : "top is " + stack.top.value);
}
class Stack {
Node top;
int size;
void push(int value) {
top = new Node(value, top);
size++;
}
int pop() {
int value = top.value;
top = top.next;
size--;
return value;
}
boolean isEmpty() {
return top == null;
}
@Override
public String toString() {
String text = "";
for (Node n = top; n != null; n = n.next) {
text += (text.isEmpty() ? "" : ", ") + n.value;
}
return "[" + text + "] (" + size + ")";
}
}
class Node {
final int value;
final Node next;
Node(int value, Node next) {
this.value = value;
this.next = next;
}
}
Collections and StringBuilder
ArrayList, HashMap, HashSet,
ArrayDeque and PriorityQueue, with generics,
the diamond and boxing, plus StringBuilder,
Character and Arrays. The library is a
separate download, made only the first time a program on the page uses
it. A HashMap or HashSet prints in the
JDK's order (the engine lays out its table as the JDK does).
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] words = {"the", "quick", "brown", "fox", "jumps",
"over", "the", "lazy", "dog", "the", "end"};
Map<String, Integer> counts = new HashMap<>();
List<String> order = new ArrayList<>();
for (String word : words) {
if (!counts.containsKey(word)) order.add(word);
counts.put(word, counts.getOrDefault(word, 0) + 1);
}
System.out.println(order.size() + " distinct words, \"the\" x" + counts.get("the"));
PriorityQueue<Integer> lengths = new PriorityQueue<>();
for (String word : order) lengths.add(word.length());
StringBuilder sb = new StringBuilder();
while (!lengths.isEmpty()) sb.append(sb.isEmpty() ? "" : " ").append(lengths.poll());
System.out.println("lengths: " + sb);
Deque<Character> stack = new ArrayDeque<>();
for (char c : "stressed".toCharArray()) stack.push(Character.toUpperCase(c));
StringBuilder reversed = new StringBuilder();
while (!stack.isEmpty()) reversed.append(stack.pop());
System.out.println(reversed + " " + Arrays.toString(new int[] {3, 1, 2}));
}
}
Sorting with comparator lambdas
A (a, b) -> … lambda orders an Arrays.sort,
a List.sort or a PriorityQueue. Sorting works
as on a JVM down to the details: the classic overflow bug of
(a, b) -> a - b puts the same elements in the same
wrong order, and an exception inside a comparator shows the
lambda's own frame.
import java.util.*;
public class Main {
public static void main(String[] args) {
int[][] intervals = {{8, 10}, {1, 3}, {2, 6}, {15, 18}};
Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
System.out.println(Arrays.deepToString(intervals));
PriorityQueue<String> shortestFirst = new PriorityQueue<>((a, b) -> {
if (a.length() != b.length()) return a.length() - b.length();
return a.compareTo(b);
});
for (String w : new String[] {"pear", "fig", "apple", "kiwi"}) shortestFirst.add(w);
StringBuilder order = new StringBuilder();
while (!shortestFirst.isEmpty()) order.append(shortestFirst.poll()).append(' ');
System.out.println(order);
Integer[] xs = {Integer.MIN_VALUE, 5, -3, Integer.MAX_VALUE};
Arrays.sort(xs, (a, b) -> a - b);
System.out.println("overflowing comparator: " + Arrays.toString(xs));
}
}
Text, formatting and random numbers
String's everyday methods, Java's regex syntax in
split and replaceAll, and
printf with Java's own rounding: %.2f of
1.005 is 1.01, where C would print 1.00.
A seeded Random gives exactly the numbers a JVM gives.
import java.util.Random;
public class Main {
public static void main(String[] args) {
String line = " Ada Lovelace, 1815; Alan Turing, 1912 ";
for (String entry : line.strip().split(";\\s*")) {
String[] parts = entry.split(",\\s*");
String name = parts[0].replaceAll("(\\w+) (\\w+)", "$2, $1");
System.out.printf("%-16s|%5d|%n", name, Integer.parseInt(parts[1]));
}
System.out.println(String.format("%.2f %.2f %,d", 1.005, 2.675, 1234567));
System.out.println("ab".repeat(3) + " " + "Mississippi".lastIndexOf("ss") + " " + String.join("-", "a", "b", "c"));
Random dice = new Random(42);
StringBuilder rolls = new StringBuilder();
for (int i = 0; i < 10; i++) rolls.append(dice.nextInt(6) + 1).append(' ');
System.out.println(rolls + "| " + Math.floorMod(-7, 3) + " " + Math.pow(2, 0.5));
}
}
Reading input
Scanner and IO.readln read the input box,
all at once, as if it were piped to java. Try the classic
trap: after nextInt(), a nextLine() returns
the rest of that line, which is empty. Clear the box and run again to
see what happens when the input runs out.
import java.util.Scanner;
void main() {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String rest = in.nextLine();
IO.println("n = " + n + ", rest of the line = [" + rest + "]");
int oldest = 0;
String name = "";
for (int i = 0; i < n; i++) {
String who = in.next();
int age = in.nextInt();
if (age > oldest) { oldest = age; name = who; }
}
IO.println("oldest: " + name + " (" + oldest + ")");
}
Classes, records, enums and exceptions
Interfaces, records (with a compact constructor that validates),
an enum, instanceof patterns, and a checked exception
of the program's own, caught with finally. A record's
toString(), the exception's class name and the
%.2f rounding are the JDK's.
import java.util.*;
interface Shape { double area(); }
record Circle(double r) implements Shape { public double area() { return Math.PI * r * r; } }
record Rect(double w, double h) implements Shape {
Rect {
if (w <= 0 || h <= 0) throw new IllegalArgumentException("bad size: " + w + " x " + h);
}
public double area() { return w * h; }
}
enum Unit { CM, M }
class NotFound extends Exception {
NotFound(String what) { super(what + " not found"); }
}
Shape find(List<Shape> shapes, String kind) throws NotFound {
for (Shape s : shapes) {
if (s instanceof Circle c && kind.equals("circle")) return c;
if (s instanceof Rect r && kind.equals("rect")) return r;
}
throw new NotFound(kind);
}
void main() {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle(1));
shapes.add(new Rect(2, 3));
try {
shapes.add(new Rect(-1, 2));
} catch (IllegalArgumentException e) {
IO.println("skipped: " + e.getMessage());
}
for (Shape s : shapes) IO.println(s + String.format(" area %.2f %s", s.area(), Unit.CM));
try {
IO.println(find(shapes, "rect"));
IO.println(find(shapes, "triangle"));
} catch (NotFound e) {
IO.println(e);
} finally {
IO.println("done");
}
}
Collections, lambdas and generics
merge with Integer::sum, a comparator chain,
a generic record and a generic trie with an inner node class,
var, and a graph as List<Integer>[].
As from the JDK's source launcher, javac's
[unchecked] warning for new ArrayList[3]
comes first on stderr; @SuppressWarnings("unchecked")
on main would silence it.
import java.util.*;
public class Main {
record Pair<A, B>(A first, B second) { }
static class Trie<V> {
class Node { Map<Character, Node> next = new TreeMap<>(); V value; }
Node root = new Node();
void put(String key, V value) {
Node n = root;
for (char c : key.toCharArray()) n = n.next.computeIfAbsent(c, k -> new Node());
n.value = value;
}
V get(String key) {
Node n = root;
for (char c : key.toCharArray()) if ((n = n.next.get(c)) == null) return null;
return n.value;
}
}
static <T extends Comparable<T>> T max(Collection<T> xs) {
T best = null;
for (T x : xs) if (best == null || x.compareTo(best) > 0) best = x;
return best;
}
public static void main(String[] args) {
String text = "the cat and the dog and the bird";
Map<String, Integer> counts = new TreeMap<>();
for (String w : text.split(" ")) counts.merge(w, 1, Integer::sum);
System.out.println(counts + " longest: " + max(counts.keySet()));
List<Pair<String, Integer>> pairs = new ArrayList<>();
counts.forEach((w, n) -> pairs.add(new Pair<>(w, n)));
pairs.sort(Comparator.comparing((Pair<String, Integer> p) -> p.second()).reversed().thenComparing(Pair::first));
System.out.println(pairs.get(0) + " " + pairs.get(1));
var trie = new Trie<Integer>();
trie.put("cat", 1);
trie.put("car", 2);
System.out.println(trie.get("car") + " " + trie.get("ca"));
List<Integer>[] graph = new ArrayList[3];
for (int i = 0; i < graph.length; i++) graph[i] = new ArrayList<>();
graph[0].add(1);
graph[1].add(2);
System.out.println(Arrays.toString(graph));
}
}
Anonymous classes and streams
An anonymous Comparator (the JDK names it
Main$1), and stream pipelines with
Collectors. A pipeline runs element by element and
stops early as the JDK's does: the peek below prints
three squares, not five, because limit(3) has enough.
import java.util.*;
import java.util.stream.*;
public class Main {
public static void main(String[] args) {
int[] nums = {4, 1, 4, 3, 1, 4};
Map<Integer, Long> freq = Arrays.stream(nums).boxed().collect(Collectors.groupingBy(n -> n, Collectors.counting()));
Comparator<Integer> byFrequency = new Comparator<>() {
public int compare(Integer a, Integer b) {
return Long.compare(freq.get(b), freq.get(a));
}
};
PriorityQueue<Integer> pq = new PriorityQueue<>(byFrequency);
pq.addAll(freq.keySet());
System.out.println(freq + " top " + pq.peek() + " " + pq.getClass().getName() + " " + byFrequency.getClass().getName());
List<String> words = List.of("stream", "lambda", "class", "java");
System.out.println(words.stream().filter(w -> w.length() > 4).map(String::toUpperCase).sorted().collect(Collectors.joining(", ", "[", "]")));
System.out.println(IntStream.rangeClosed(1, 5).map(i -> i * i).peek(i -> System.out.print(i + " ")).limit(3).sum());
}
}
Local classes, subList and raw types
A record and a class declared inside main get javac's
names (Main$1Circle); subList is a view, so
sorting and clearing it changes the list behind it; and a raw
List compiles with javac's [unchecked]
warnings, which arrive on stderr before the output.
import java.util.*;
public class Main {
interface Shape { double area(); }
public static void main(String[] args) {
record Sq(double s) implements Shape { public double area() { return s * s; } }
class Circle implements Shape {
final double r;
Circle(double r) { this.r = r; }
public double area() { return 3 * r * r; }
public String toString() { return "Circle(" + r + ")"; }
}
List<Shape> shapes = new ArrayList<>(List.of(new Sq(2), new Circle(1), new Sq(1), new Circle(2)));
List<Shape> window = shapes.subList(1, 3);
window.sort(Comparator.comparingDouble(Shape::area));
System.out.println(shapes + " " + window.getClass().getName() + " " + new Circle(0).getClass().getName());
window.clear();
System.out.println(shapes);
List legacy = new ArrayList();
legacy.add("old");
List<String> typed = legacy;
System.out.println(typed.get(0).length());
}
}
Sealed types and pattern matching
A sealed interface of records, taken apart by record patterns in a
switch that needs no default because it
covers every permitted subclass. Guards (when),
case null, and float and byte
arithmetic print as on JDK 25.
import java.util.*;
public class Main {
sealed interface Shape permits Circle, Square, Group { }
record Circle(float r) implements Shape { }
record Square(float side) implements Shape { }
record Group(String name, List<Shape> parts) implements Shape { }
static float area(Shape s) {
return switch (s) {
case Circle(float r) -> 3.14159f * r * r;
case Square(var side) -> side * side;
case Group(String name, var parts) -> {
float total = 0;
for (Shape p : parts) total += area(p);
yield total;
}
};
}
static String describe(Object o) {
return switch (o) {
case null -> "nothing";
case Shape s when area(s) > 10 -> "a big shape";
case Shape s -> "a shape of area " + area(s);
case Byte b -> "the byte " + b;
default -> "something else";
};
}
public static void main(String[] args) {
Shape g = new Group("pair", List.of(new Circle(1.5f), new Square(0.1f)));
System.out.println(area(g));
for (Object o : new Object[] {g, new Square(2), (byte) -128, null, 0.1f}) System.out.println(describe(o));
byte b = 120;
b += 10;
short s = (short) 70000;
System.out.println(b + " " + s + " " + (float) 0.1 + " " + 1.1f * 3);
}
}
BigDecimal, BigInteger, EnumMap and EnumSet
Money in BigDecimal (exact, unlike
0.1 + 0.2), prices kept per enum constant in an
EnumMap, and a 40-digit factorial in
BigInteger, all printed digit for digit as JDK 25 prints
them.
import java.math.*;
import java.util.*;
public class Main {
enum Item { COFFEE, BAGEL, JUICE }
public static void main(String[] args) {
Map<Item, BigDecimal> prices = new EnumMap<>(Item.class);
prices.put(Item.JUICE, new BigDecimal("3.75"));
prices.put(Item.COFFEE, new BigDecimal("2.50"));
prices.put(Item.BAGEL, new BigDecimal("1.99"));
BigDecimal subtotal = BigDecimal.ZERO;
for (BigDecimal p : prices.values()) subtotal = subtotal.add(p.multiply(BigDecimal.valueOf(3)));
BigDecimal tax = subtotal.multiply(new BigDecimal("0.0825")).setScale(2, RoundingMode.HALF_UP);
System.out.println(prices + " subtotal " + subtotal + " tax " + tax + " total " + subtotal.add(tax));
System.out.println(BigDecimal.ONE.divide(new BigDecimal("3"), 20, RoundingMode.HALF_EVEN) + " " + (0.1 + 0.2) + " vs " + new BigDecimal("0.1").add(new BigDecimal("0.2")));
EnumSet<Item> breakfast = EnumSet.of(Item.BAGEL, Item.COFFEE);
System.out.println(breakfast + " " + EnumSet.complementOf(breakfast));
BigInteger f = BigInteger.ONE;
for (int i = 2; i <= 40; i++) f = f.multiply(BigInteger.valueOf(i));
System.out.println("40! = " + f + " mod 1e9+7 = " + f.mod(BigInteger.valueOf(1_000_000_007)));
}
}
Fast input and output, and static imports
The competitive programmer's template: BufferedReader
and StringTokenizer read the input box, and
PrintWriter buffers the output. The second
PrintWriter is never flushed, so, as on the JDK, its line
never appears. Remove out.flush() to see the first one
vanish too. import static brings in max,
abs and sqrt.
import java.io.*;
import java.util.*;
import static java.lang.Math.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
StringTokenizer st = new StringTokenizer(br.readLine());
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
long sum = 0, largest = 0;
for (int i = 0; i < n; i++) {
long x = Long.parseLong(st.nextToken());
sum += x;
largest = max(largest, abs(x));
}
out.printf("sum %d, largest magnitude %d, sqrt %.3f%n", sum, largest, sqrt(largest));
out.flush();
PrintWriter lost = new PrintWriter(System.out);
lost.println("never flushed, so never printed");
System.out.println("done");
}
}
Initializer blocks and text blocks
A static block fills an enum's lookup map once, an
instance block runs before every constructor's body, and a text block
keeps a multi-line template readable: its indentation up to the
closing """ is stripped, as javac strips it.
import java.util.*;
public class Main {
enum Op {
ADD('+'), SUB('-'), MUL('*');
private static final Map<Character, Op> BY_SYMBOL = new HashMap<>();
static {
for (Op op : values()) BY_SYMBOL.put(op.symbol, op);
}
final char symbol;
Op(char symbol) {
this.symbol = symbol;
}
}
private final List<String> log = new ArrayList<>();
{
log.add("instance block ran first");
}
Main() {
log.add("then the constructor");
}
public static void main(String[] args) {
String report = """
Operators:
%s
Log: %s
""".formatted(Op.BY_SYMBOL.get('*') + " for '*'", new Main().log);
System.out.print(report);
System.out.println(report.lines().count() + " lines");
}
}
Enum constants with bodies, and Interface.super
Each constant of Op brings its own apply:
javac makes it an anonymous subclass of the enum (Main$Op$1),
while getDeclaringClass() is still Op. The
duck combines two interfaces' default methods with
Swimmer.super and Flyer.super.
public class Main {
interface Swimmer {
default String move() { return "swims"; }
}
interface Flyer {
default String move() { return "flies"; }
}
static class Duck implements Swimmer, Flyer {
public String move() { return Swimmer.super.move() + " and " + Flyer.super.move(); }
}
enum Op {
PLUS("+") {
int apply(int a, int b) { return a + b; }
},
TIMES("*") {
int apply(int a, int b) { return a * b; }
};
final String symbol;
Op(String symbol) { this.symbol = symbol; }
abstract int apply(int a, int b);
}
public static void main(String[] args) {
System.out.println("A duck " + new Duck().move());
for (Op op : Op.values()) {
System.out.println("6 " + op.symbol + " 7 = " + op.apply(6, 7) + " (" + op.getClass().getName() + ", declared in " + op.getDeclaringClass().getSimpleName() + ")");
}
}
}
Practice mode: test cases for a method
With a practice attribute, Run calls one method with test
cases instead of running main, and reports each case.
This solution has a bug; fix the comparison and run it again. The
results also arrive in playpad-output as
detail.cases, for your own grading.
class Solution {
// The first index whose value is at least target.
static int lowerBound(int[] sorted, int target) {
int lo = 0, hi = sorted.length;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (sorted[mid] <= target) lo = mid + 1;
else hi = mid;
}
return lo;
}
}
Errors read like the JDK's
Compile errors use javac's wording, carets and order;
exceptions print Java stack traces, with the JDK's own
NullPointerException messages. Both are checked against a real JDK 25,
so what a learner sees here is what they will see from
java Main.java.
void main() {
int count = "three";
IO.println(total);
}
String find(String[] names, char initial) {
for (int i = 0; i < names.length; i++) {
if (names[i].charAt(0) == initial) return names[i];
}
return null;
}
void main() {
String[] names = {"Ada", "Grace", "Linus"};
IO.println(find(names, 'G').length());
IO.println(find(names, 'Z').length());
}
Stop, and one worker for the page
Every Java widget on a page shares one worker, so the engine starts once.
Run the first widget, then the second: the second shows
Queued… until it gets its turn. Its own Stop withdraws it
without touching the first, and the first one's Stop ends the loop. A
program left running is stopped after 200 million steps (a few seconds
for this one; an empty loop gets there in well under a second), with a
note explaining why.
void main() {
IO.println("counting forever...");
StringBuilder line = new StringBuilder();
for (int i = 0; ; i++) {
line.setLength(0);
line.append(i).append(" squared is ").append((long) i * i);
}
}
void main() {
IO.println("my turn");
}
What is in the subset
Supported: compact source files and classic classes; several
classes per file, nested and inner classes; constructors,
this(...), new, fields and methods on any
object, private, toString() with
@Override; inheritance, interfaces, instanceof
patterns, enums and records; try/catch/finally,
throw, custom and checked exceptions; int, char,
boolean, long, double,
String and arrays of any dimension, including arrays of
objects; static and instance methods with overloading and recursion;
if, while, do, for
and enhanced for, switch statements and
expressions, labeled break/continue,
return, ?:; Math and
java.util.Random; String's everyday
methods with Java's regex syntax, String.format and
printf;
System.out, System.err,
System.exit, System.arraycopy,
IO.print/println/readln and
Scanner over the input box; import,
generics at use sites, boxing, ArrayList,
HashMap, HashSet, ArrayDeque,
PriorityQueue, StringBuilder,
Integer/Long/Double/Character/Boolean
Arrays, List.of/Map.of,
TreeMap, TreeSet, LinkedList
and Stack; lambdas and method references for any
functional interface, with Comparator's combinators,
merge and computeIfAbsent; generic classes
and methods, var, varargs, and the
@Override/@SuppressWarnings annotations, with
javac's warnings; anonymous and local classes; raw types;
subList; streams and Collectors;
float, byte and short;
sealed classes and pattern matching in switch and
instanceof; BigInteger,
BigDecimal, EnumMap and
EnumSet; BufferedReader,
StringTokenizer, StreamTokenizer and
PrintWriter; static imports; initializer blocks and text
blocks; enum constants with bodies and Interface.super.
Not yet: parallel streams, var lambda parameters
and files, among others. These are reported as
not supported in this version, never run with a different
meaning. The full table, method by method, is
JAVA-COMPATIBILITY.md.
Java widgets fire the same events as every other language
(playpad-run, playpad-output,
playpad-error), so answer checking works the same way:
compare stdout in playpad-output. Java is a trademark of Oracle and/or its
affiliates; this engine is not affiliated with or certified by Oracle.