hello, world
from void main() to public static void main(String[] args), and why both exist.
- chapter
- chapter 01.03
- reading time
- 6 min read
since java 25, a whole program is void main() { IO.println("hello, world"); }. the classic public static void main(String[] args) still works and you'll see it everywhere: it's the same program with the scaffolding written out. this chapter is about what each piece of that scaffolding does.
the picture
make a file called Main.java, put three lines in it, run it:
void main() {
IO.println("hello, world");
}hello, world
$ java Main.java
hello, worldthat's a real, complete java program. no class, no public, no static. it's called a compact source file, and it became a final feature in java 25 (JEP 512).
for almost 30 years before that, the first program anyone wrote in java looked like five lines of ceremony around one line of work. you'll still see that version in every book, tutorial and codebase, so you need to read it fluently. the good news: it's the same program. the extra words each do one small job.
from void main() to public static void main
void main() {IO.println("hello, world");}
a complete program. save it as Main.java, run java Main.java. no class, no static, no String[] args.
so when you see public static void main(String[] args), read it as: "a method anyone can call (public), that doesn't need an object (static), returns nothing (void), is called main, and receives the command-line words (String[] args)".
public class Main {
public static void main(String[] args) {
System.out.println(args.length + " args: " + String.join(", ", args));
}
}$ java Main.java one two "three four"
3 args: one, two, three fourthe shell splits on spaces (quotes keep words together), and args is just a String[] array holding what's left after the class name.
main receives for java Main.java one two "three four". the class name and the java command itself are not in there (unlike C's argv).public class Main {
public static void main(String[] args) {
System.out.println(args.length);
}
}you run it with plain java Main.java, no arguments. what prints?
which main runs
a class can have more than one method called main. the launcher (the java command) has a fixed rule for which one it calls.
class Main { void main() { ... }}
- 1.new Main() (it's an instance method, so it needs an object)
- 2.obj.main()
main(String[]), a main(), both, or neither. the one with String[] always wins. an instance main means the launcher creates the object first. the error is the real one from jdk 25.the full rule from JEP 512: if the class has a main(String[]) (declared or inherited), run that. otherwise, if it has a main(), run that. otherwise, error. if the chosen one isn't static, the launcher calls the class's no-argument constructor first, then calls main on that object.
what a compact file gives you
a compact source file isn't a toy mode. it's normal java with three things done for you:
- a class around everything. fields and methods you write at the top level become members of a class named after the file. it's
finaland you can't refer to it by name. import module java.base. every public class injava.util,java.io,java.time,java.mathand friends is already imported.List,Map,ArrayList,LocalDate: just use them.IO.IO.println,IO.printandIO.readlnlive injava.lang, so they're available everywhere (in normal classes too).
String greeting = "hi";
void main() {
IO.println(greeting + " from " + getClass().getName());
IO.println(List.of(1, 2, 3));
}hi from Main [1, 2, 3]
greeting is a field, main is an instance method, and getClass().getName() proves there really is a class called Main under there. List worked without an import. ask the class file itself and it agrees:
$ javac Main.java && javap -p Main
Compiled from "Main.java"
final class Main {
java.lang.String greeting;
Main();
void main();
}when a compact file grows up, you don't rewrite it: wrap it in class Main { ... }, add imports for whatever you used, done.
how long this took to land+
the idea went through four previews before it was final. JEP 445 (java 21) called them "unnamed classes". JEP 463 (22) renamed them "implicitly declared classes", and JEP 477 (23) added the automatic java.base import plus a java.io.IO class whose println you could call bare. JEP 495 (24) only changed the name, to "simple source files". then JEP 512 (25) finalized it as "compact source files", with three last-minute changes: IO moved to java.lang, you now write IO.println instead of a bare println, and IO prints through System.out instead of the system console, so it plays nicely with redirection and pipes. that's how preview features are supposed to work: ship, listen, adjust. more in preview features.
void main() { IO.println("hi"); }is a complete java 25 program.public static void main(String[] args)is the same thing with the scaffolding written out.staticmeans no object needed.String[] argsholds the command-line words, nevernull.- the launcher prefers
main(String[])overmain(). an instance main gets a fresh object first. - compact files import all of
java.basefor you. when the file grows up, wrap it in a class.