Side-by-side, interactive cheatsheets for Java programmers
comparing Java to other languages. Every example runs live in your browser — no setup, no installation.
Choose your own path by reordering languages
The language that trades Java's ceremony for expressiveness, Ruby does in one line what Java does in ten — no type declarations, no class wrappers, no boilerplate, just code that reads like English.
3.times, array.each, map, select, reduce built into the languageinclude Comparable or Enumerable and gain 50+ methods for freeString, Integer, or any existing class at any timecase/in with array, hash, and type patterns, stable since Ruby 3.0Java reimagined without the ceremony. Go keeps the static types and compiled performance Java developers expect, then strips away generics boilerplate, checked exceptions, class hierarchies, and XML config — leaving clean, readable code that deploys as a single binary.
(result, error) return pairs make error paths visible in the signature, not hidden in throws clausesimplements keyword needed-jar flag; go build produces one fileShares your name and almost nothing else. Java and JavaScript both use C-family braces, and then diverge on every assumption underneath — what a class is, what this means, whether integers exist, and whether your code runs on threads.
this is decided by the call, not the class — a detached method loses its receiver, unlike a Java method reference7 / 2 is 3.5 and integers past 2^53 silently lose precisionsynchronized, no locks, no data races, and no blocking Future.get()class is syntax over prototypes and declares no type; any object with the right properties is acceptedthrows clause, and a single untyped catch bindingConcise, dynamic, and dominant in data and scripting, Python trades Java's static guarantees for speed of writing — and rules data science and machine learning.
main boilerplate — a top-level print() is a whole programstream().map().collect() pipelinethrows@dataclass as the counterpart to a Java recordKotlin is what Java would be if it were redesigned today. Null safety in the type system, data classes in one line, extension functions instead of utility classes, when instead of switch pyramids, and coroutines instead of CompletableFuture — all on the JVM, fully interoperable with every Java library.
String can never be null; String? must be handled at compile time; NullPointerException becomes a compile error instead of a runtime surprisedata class Person(val name: String, val age: Int) generates equals, hashCode, toString, and copy(); Java needs a record or 50+ linesconnect(host = "x", ssl = true)"racecar".isPalindrome() instead of StringUtils.isPalindrome("racecar")suspend fun makes async code read like sequential code; replaces CompletableFuture chains with straightforward val result = fetchUser(42)The JVM's guarantees, re-derived without a garbage collector. Rust replaces the GC Java developers take for granted with compile-time ownership tracking — and closes the gaps Java's null, unchecked exceptions, and type erasure leave open, catching them before the program ever runs instead of during it.
null — absence is Option<T>, and the compiler forces you to handle it; unlike Java's opt-in Optional<T>, there is no bare nullable type left underneath to bypass itResult<T, E> with the ? operator for propagation, in place of Java's checked/unchecked exception hierarchy and try/catch/throwsimpl Trait for Type works even on types you don't own, something no Java interface can do without a wrapper classenum even with Java 21's sealed interfaces, records, and pattern matching closing part of the gapList<String> and List<Integer> collapse into one type in the JVMThe iOS side of the mobile world, for the Android/Java developer. Swift keeps Java's static typing and OOP but bakes null-safety into the type system, favors value types over references, and replaces interfaces with protocols and extensions — familiar territory with the sharp edges filed off.
?) make nullability part of the type — the compiler eliminates the NullPointerException class of buglet/var replacing finalInt, and conform existing types retroactivelythrows/try/do-catch with no checked exceptions, plus guard let and trailing closuresThe same words, and almost none of the same meanings. TypeScript checks types before the program runs, calls them interfaces and generics, and then does something you have never had to reason about: it throws the whole type system away before anything executes.
implements clause and no adapter class to writeClass object, no reflection, no instanceof for an interface, and JSON.parse hands back unchecked any"GET" | "POST") do the work of enums and sealed hierarchies without declaring a type per casestrictNullChecks a string genuinely cannot be null — the one place the checking is stricter than Java'sPartial, Pick, keyof and mapped types compute types from other types, which Java cannot do at any levelnumber type (a double, so 7 / 2 is 3.5), one thread, no equals/hashCode, and no checked exceptionsA modern Lisp on the JVM that replaces inheritance hierarchies with data, Clojure trades Java's mutable objects and class hierarchies for immutable persistent data structures, first-class functions, and a REPL-driven workflow.
conj and assoc return new collections; the originals are never modified, eliminating the defensive copying that Java requires(+ 1 2), (str "Hello" name), (map f coll) — the same syntax for function calls, macros, and data literals(->> coll (filter even?) (map #(* % 2))) is lazy by default, with no .collect(Collectors.toList()) neededC# does in one line what Java does in five. Properties replace getters/setters, optional parameters replace overloads, LINQ replaces verbose Streams, and async/await replaces CompletableFuture — while staying on the same statically-typed OOP foundation Java developers already know.
public string Name { get; set; } replaces pairs of getName()/setName() methods with field-like access syntaxfrom x in list where x > 5 select x reads like SQL and compiles to the same lazy pipeline as Java Streams, without .stream() boilerplateasync/await as a first-class language feature — no CompletableFuture chains, no .get() blocking; async code reads like synchronous codeThe process dies at the end of every request, and everything you know about application state is wrong. No static field survives, no pool is warm, no thread exists — and no shared mutable state can be corrupted, which is why PHP sidestepped a decade of concurrency bugs the JVM world fought. Modern PHP 8 has enums, readonly, match, named arguments and attributes; the mental image from 2009 is the thing to replace.
static fields are per-request, there is no warmup and no connection pool, and anything that must survive goes to Redis or the databaseExecutorService, no synchronized, no memory model — so concurrency is more processes, a queue worker, or Fibers under an event loopdeclare(strict_types=1) makes them refuse coercion — a different trade from generics erased at compile timearray is List, Map and tuple at once, and it is copied on assignment, which surprises Java developers more than anything else here@template docblocks read by PHPStan or Psalm are the ecosystem answer, and level 9 is roughly -Xlint:all taken seriouslyreadonly, constructor promotion, match, named arguments and first-class callables are all here — but no records, no sealed types and no pattern matchingdefault methods deliberately do not crossFunctional meets object-oriented on the JVM — Scala blends immutable values, powerful pattern matching, and a rich type system into a concise language that feels like the Java you always wished you had.
val is immutable by default — final without the verbosity, and the preferred choice everywherecopy, and structural equality out of the boxOption[T] replaces null — absence is explicit in the type, not a runtime NullPointerException waiting to happenflatMap/map/filter — monadic pipelines that are more readable than Stream chainsstatic — companion objects replace static members with first-class singleton objects