Free lesson · Java Basic To Advance
First Program
Hello, World — But Properly
Every programming course has a "Hello, World" Topic. Most of them just show the canonical example and move on. We're going to do more — write Hello World, then explain every single part of it, then write a few variations, then run it from the command line and trace what actually happens.
By the end of this Topic, you'll have written and run real Java code, and you'll understand why the code looks the way it does.
The Canonical Hello World
The classic Java Hello World:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
That's seven words of actual output ("Hello, world!") wrapped in 80+ characters of ceremony. Java is famously verbose for tiny programs. Let me walk through every part.
public class HelloWorld — declares a class named HelloWorld. The public access modifier means this class is visible from anywhere. Java requires all top-level code to be inside a class (with one exception we'll mention shortly).
public static void main(String[] args) — the entry point of the program. The JVM looks for a method matching this exact signature when you run a Java class. Each word matters:
public— accessible to the JVMstatic— belongs to the class itself, not to instances (no need to create an instance to call it)void— returns nothing (no exit code at the language level, though the JVM has one)main— the conventional name the JVM looks forString[] args— command-line arguments passed to the program, as an array of strings
If you misspell main, leave off static, change the return type, or use any other parameter signature, the JVM won't find an entry point and refuses to run.
System.out.println("Hello, world!"); — prints a string to standard output, followed by a newline. Breaking this down:
System— a class injava.langproviding access to system facilities.out— a static field onSystem, the standard output stream (aPrintStream).println(...)— a method onPrintStreamthat prints its argument followed by a newline"Hello, world!"— a string literal, the argument we're passing
Java statements end with semicolons. That's required, not optional.
The braces. Java uses { and } to delimit blocks — classes, methods, loops, conditionals. Convention puts the opening brace at the end of the line that starts the block, not on its own line (Java convention differs from C# convention here).
Interactive animation: Why main is static - otherwise the JVM would need an instance, a constructor, and arguments it cannot know.
Running the Program
Save the code above to a file named HelloWorld.java. The file name must match the public class name. Java is strict about this.
From the command line:
# Compile
javac HelloWorld.java
# Run
java HelloWorld
You should see Hello, world! printed.
What just happened:
javac HelloWorld.javainvoked the Java compiler, which read the source and producedHelloWorld.class— the bytecodejava HelloWorldinvoked the JVM, which loadedHelloWorld.class, found themainmethod, and executed itmaincalledSystem.out.println, which output the string
Note that the java command takes a class name (no .class extension), not a file name. The JVM searches the classpath for a file matching that class name.
graph LR
A[HelloWorld.java<br/>source code] -->|javac| B[HelloWorld.class<br/>bytecode]
B -->|java| C[JVM loads class]
C --> D[JVM finds main method]
D --> E[JVM executes bytecode]
E --> F["Hello, world!"<br/>printed to stdout]
style A fill:#7c3aed,color:#fff
style B fill:#10b981,color:#fff
style E fill:#3b82f6,color:#fff
style F fill:#f59e0b,color:#fff
This diagram shows the compile-and-run cycle for a Java program. You start with HelloWorld.java, a source file. The javac compiler reads it and produces HelloWorld.class, a bytecode file. When you run java HelloWorld, the JVM loads that class file into memory. The JVM looks for a method named main with the specific signature taking a String array. It then executes the bytecode for that method, which calls System.out.println, which writes "Hello, world!" to standard output. This is the cycle for every Java program, however complex.
Modern Java: Hello World, Shorter
Java 21 introduced "unnamed classes and instance main methods" (technically still in preview in some versions). This lets you write:
void main() {
System.out.println("Hello, world!");
}
No public class wrapper. No static. No String[] args parameter. Just the method.
To run with this syntax (Java 21+):
java --enable-preview --source 21 HelloWorld.java
This feature is aimed at beginners and competitive programming. Production code still uses the explicit class syntax. We mention it because (1) it answers the "why is Hello World so verbose?" complaint, and (2) interviewers occasionally ask about recent language features.
Interactive animation: The classic HelloWorld beside the Java 21 version - no public class wrapper, no static, no String[] args.
Variations to Internalize
Let me show a few small variations on Hello World that build understanding.
Echoing command-line arguments:
public class Echo {
public static void main(String[] args) {
for (String arg : args) {
System.out.println(arg);
}
}
}
Run with: java Echo hello world from command line. Each argument prints on its own line.
Reading from standard input:
import java.util.Scanner;
public class Greet {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("What's your name? ");
String name = scanner.nextLine();
System.out.println("Hello, " + name + "!");
scanner.close();
}
}
This demonstrates the import statement (covered in detail in Module 12), Scanner for input, and string concatenation with +.
Using printf for formatted output:
public class Format {
public static void main(String[] args) {
String name = "Olena";
int age = 35;
double height = 1.68;
System.out.printf("Name: %s, Age: %d, Height: %.2f%n", name, age, height);
}
}
%s is a string placeholder, %d is an integer, %.2f is a float with 2 decimal places, %n is a platform-appropriate newline. Java's format specifiers come from C's printf.
What javac Produces
A small experiment to understand what compilation actually produces. Compile HelloWorld.java and then inspect the result:
javac HelloWorld.java
javap -c HelloWorld
javap -c disassembles the class file, showing the bytecode in human-readable form. You'll see something like:
Compiled from "HelloWorld.java"
public class HelloWorld {
public HelloWorld();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #13 // String Hello, world!
5: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
This is the bytecode that the JVM actually executes. The numbers in the left column are bytecode offsets. Each opcode (aload_0, invokespecial, getstatic) is a JVM instruction. The #N references are pointers into the constant pool (constants and references stored in the class file).
You don't need to read or write bytecode in practice — javac handles compilation. But seeing bytecode at least once makes the abstract "compiles to bytecode" claim concrete.
Common Pitfalls
Warning: File name doesn't match public class name. Java requires
public class HelloWorldto be in a file namedHelloWorld.java. Mismatches produce errors like "class HelloWorld is public, should be declared in a file named HelloWorld.java."Forgetting
staticonmain. A non-staticmainwon't be found by the JVM. The error is "Main method not found in class HelloWorld."Misspelling
main.Main,MAIN,main()(withoutString[] args) — none of these work. The JVM looks for the exact signaturepublic static void main(String[] args).Missing semicolons. Every statement must end with one. Java will not silently forgive you.
Running
java HelloWorld.class. You run with the class name, not the file name. Usejava HelloWorld.Running from the wrong directory. The class file needs to be in your current directory or on the classpath. If you compile in one directory and try to run from another, the JVM won't find the class.
Interactive animation: Six first-program errors and what Java says for each - learn the message, not just the mistake.
Why This Matters in Interviews
Interview: First-program-style questions don't appear in senior interviews, but the parts of Hello World — class structure, the
mainsignature,System.out.println— are foundational vocabulary that everything builds on. Senior interviews assume you can write this fluently and probe deeper material.What does come up: occasionally, interviewers ask "why is
mainstatic?" The answer: because the JVM needs to invoke it without first creating an instance of the class. Ifmainweren't static, the JVM would need to create an instance, which would require a constructor, which raises questions about which constructor to call and with what arguments. Makingmainstatic sidesteps all of that.
Try It
Exercise: Write and run all three example programs from this Topic:
HelloWorld.java— the canonical versionEcho.java— echoes command-line argumentsGreet.java— reads input and greets the userFor each program:
- Compile with
javac- Run from the command line
- Run
javap -c <ClassName>to see the bytecodeThen try the modern variant — if you have Java 21+, write the unnamed-class version of HelloWorld and run it with
--source 21. Compare the bytecode it produces (javap -c HelloWorld) to the original. You'll see the JVM still treats it as a class under the hood.Don't skip the bytecode step. Seeing what
javacproduces makes the abstract "compiles to bytecode" claim concrete in a way no diagram can match.