Java’s “Hello, World!” is more than a rite of passage—it’s a snapshot of the language’s ergonomics at a point in time. In Java 8 (2014), it taught structure and ceremony. In the Java 21–25 era, it showcases a leaner, faster, more ergonomic platform that scales from scripts to cloud-native services. This article compares how developers say “Hello” in Java 8 versus modern Java, using Java 25 as a shorthand for the contemporary toolchain and features arriving through Java 21–23 and expected maturity by Java 25.
TL;DR: Modern Java keeps everything you know from Java 8, but lets you write, run, package, and even parallelize your “Hello, World!” with less boilerplate and better tooling.
The Classic: “Hello, World!” in Java 8
In Java 8, everything starts with a class and a static main
:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Run it with two steps:
javac Hello.java
java Hello
What this teaches:
- Structure is explicit: class, method, signature.
- Toolchain is explicit: compile, then run.
- Strong conventions: public class matches filename.
Java 8 remains an LTS many systems still target. But if this is your first and only “Hello,” you’re missing a decade of developer ergonomics.
The 2025 Experience: Saying Hello with Modern Java
By 2025, Java 25 is expected to be the next LTS after Java 21. Many improvements introduced since Java 9 drastically reduce the friction between idea and execution.
Option 1: Still classic—and still valid
Your old “Hello” still works forever:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
But you can now run it in one step (no separate javac
) thanks to single-file source launch:
java Hello.java
- Introduced by JEP 330: Launch Single-File Source-Code Programs (Java 11)
Option 2: Minimal Java with unnamed classes (preview today, likely simpler in JDK 25)
Modern Java is actively simplifying the first contact. With unnamed classes and instance main
methods (previewed in JDK 21–23), you can write:
void main() {
System.out.println("Hello, World!");
}
Run it on a preview-enabled JDK (adjust the version to your JDK):
java --enable-preview --source 23 Hello.java
This is still “Java” (strong typing, standard library), just without the ceremony for tiny programs.
Option 3: One-liner in JShell
For exploration and teaching, JShell (Java’s REPL) is perfect:
$ jshell
jshell> System.out.println("Hello, World!");
Hello, World!
- JShell arrived with JEP 222 (Java 9).
Comparing Ways to Say Hello
Code verbosity
- Java 8: requires a class and static
main
. - Modern Java: can be a single method (preview) or a one-liner in JShell.
- Static typing and the platform’s safety remain intact; the ceremony is optional for small apps.
Build and run flow
- Java 8:
javac Hello.java
java Hello
- Java 11+:
java Hello.java
(compiles and runs in one command for simple programs)
- Java 21–25 with unnamed classes (if/when finalized):
java Hello.java
on a file containing justvoid main() { ... }
Platform ergonomics
- Stronger defaults and better out-of-the-box tooling
- Less boilerplate for getting started
- Smoother path from script to app to packaged binary
Modern Flourishes: Strings, Text, and Templates
The world’s most famous greeting can be more expressive with modern Java features.
Text blocks for multi-line output
Text blocks (Java 15, JEP 378) help with formatted strings:
public class HelloBlock {
public static void main(String[] args) {
String banner = """
+-----------------+
| Hello, World! |
+-----------------+
""";
System.out.println(banner);
}
}
String templates (preview in 21–23)
String templates simplify interpolation. If you’re on a JDK with templates enabled:
// Requires --enable-preview and the correct --source version on JDK 21–23
void main() {
String name = "World";
System.out.println(STR."Hello, \{name}!");
}
Run with:
java --enable-preview --source 23 HelloTemplates.java
- See JEP 430 and subsequent updates (e.g., JEP 465). If finalized by Java 25, expect to drop the preview flags.
For teaching, templates plus JShell make micro-examples readable and fast to iterate on, without detours into
String.format
or concatenation.
Hello, Concurrency: Virtual Threads
While “Hello, World!” is single-threaded, modern Java makes it trivial to show concurrent output—useful in courses or demos.
Java 8 approach
public class HelloThread {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> System.out.println("Hello from a thread!"));
t.start();
t.join();
}
}
Java 21+ with virtual threads
Virtual threads (Java 21, JEP 444) make lightweight concurrency straightforward:
public class HelloVirtual {
public static void main(String[] args) throws InterruptedException {
Thread.startVirtualThread(() -> System.out.println("Hello from a virtual thread!")).join();
}
}
- Same API, radically lower overhead for many concurrent tasks.
- In teaching contexts, this shows modern Java’s scalability without introducing frameworks.
Packaging and Distribution: From Classpath to Custom Runtimes
Java 8 shipped a monolithic JRE. Modern Java lets you tailor and package runtimes, which matters even for tiny apps.
Custom runtime with jlink
With modules (Java 9) came jlink, letting you create a trimmed runtime:
# Compile your app
javac Hello.java
# Build a runtime image with only needed modules
jlink --add-modules java.base --output hello-runtime
# Run your app using the minimized runtime
./hello-runtime/bin/java Hello
- This reduces distribution size and startup time—relevant even for “Hello” in containerized demos.
Native installers with jpackage
Create platform installers/bundles with jpackage:
# Package a jar first
jar --create --file hello.jar -e Hello Hello.class
# Produce a native installer/bundle
jpackage --name HelloApp --input . --main-jar hello.jar
- Great for student projects or desktop utilities.
- On CI, this turns “Hello” into a real distributable deliverable.
Performance and Startup: The “Hello” You Don’t See
Even “Hello, World!” benefits from platform improvements:
- Class Data Sharing and AppCDS (JEP 310) can improve startup by sharing common class metadata across JVM processes.
- Improved GC options (G1 by default, ZGC and Shenandoah in newer releases) reduce memory overhead and latency for tiny services.
- Container awareness across modern JDKs ensures proper memory/CPU sizing in Docker/Kubernetes without exotic flags.
While your print statement looks the same, the journey from process start to output is faster and lighter on modern JDKs.
Developer Workflow: Scripts, Sources, and Repls
Modern Java supports multiple “Hello” workflows:
- Single-file scripts with a shebang (Unix):
//#!/usr/bin/env java --source 23 --enable-preview
void main() {
System.out.println("Hello, script!");
}
Make it executable and run as a script. Ideal for demos and tooling.
- One-step compilation and execution:
java Hello.java
- Rapid prototyping in JShell:
jshell> var greeting = "Hello, World!";
jshell> System.out.println(greeting);
Hello, World!
Today’s Java welcomes quick feedback loops. You choose the path: REPL, script, single-file run, or classic compile-run cycle.
Migration Tips for Students and Teams
If you’re coming from Java 8 or teaching across versions, keep these in mind:
- Use the right language level
javac --release 8 ...
produces bytecode compatible with Java 8.- For modern code, compile with the JDK you target (e.g., 21 or 25 when available).
- Adopt safe modern defaults
- Prefer G1 (default in modern JDKs).
- Enable CDS/AppCDS for faster startup in repeated runs.
- Favor single-file runs and JShell for learning
- This reduces ceremony and keeps the focus on core concepts.
- Experiment with previews—cautiously
- Unnamed classes and string templates are fantastic for teaching and prototyping.
- Use
--enable-preview --source
when running examples, and track their JEP status.
- Embrace packaging when shipping
jlink
andjpackage
turn simple apps into small, shippable artifacts without external runtimes.
Side-by-Side: Minimal Examples
Java 8 canonical
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Java 21–25 minimal (preview today)
void main() {
System.out.println("Hello, World!");
}
Run with:
java --enable-preview --source 23 Hello.java
JShell one-liner
jshell> System.out.println("Hello, World!");
Hello, World!
References and Further Reading
- Launch Single-File Programs (JEP 330): https://openjdk.org/jeps/330
- JShell (JEP 222): https://openjdk.org/jeps/222
- Text Blocks (JEP 378): https://openjdk.org/jeps/378
- Virtual Threads (JEP 444): https://openjdk.org/jeps/444
- Unnamed Classes and Instance Main Methods (Preview) (JEP 445/463): https://openjdk.org/jeps/445 and https://openjdk.org/jeps/463
- String Templates (JEP 430/465): https://openjdk.org/jeps/430 and https://openjdk.org/jeps/465
- jlink (JEP 282): https://openjdk.org/jeps/282
- jpackage (JEP 392): https://openjdk.org/jeps/392
- AppCDS (JEP 310): https://openjdk.org/jeps/310
Final Thoughts
From Java 8 to Java 25, the journey of “Hello, World!” mirrors the platform’s evolution: the classic path remains, but you now have faster on-ramps, lighter packaging, improved startup, and modern quality-of-life features. For students, that means less friction in learning. For professionals, it means quicker prototypes, slimmer deployments, and fewer barriers between concepts and running code.
In short: Java in 2025 still feels like Java—just more welcoming when you say “Hello.”