RizTech Academy logo
RizTech Academy
Getting StartedLesson 4 of 420 min

Your first program, and what public static void main means

Every Java tutorial starts with this program, and almost every one of them says "do not worry about what these words mean yet". Then it never comes back. People end up typing public static void main(String[] args) from memory for two years without knowing what any of it does.

We are going to come back to it in this lesson, because all five words are explainable now and each one teaches something about the language.

The program

Create a file called Hello.java — the capital H matters, and you will see why in a moment — and type this in. Do not copy and paste it. Typing it is how your fingers learn where the braces and semicolons go, and the errors you make while typing it are the point of the second half of this lesson.

public class Hello {
    public static void main(String[] args) {
        System.out.println("Namaste, Pune");
    }
}

Running it by hand, once

Use the terminal for this first one, before letting the IDE do it. You should see the two steps at least once.

javac Hello.java
java Hello
Namaste, Pune

javac Hello.java produced a new file next to your source — Hello.class, the bytecode from the previous lesson. java Hello started the JVM and ran it.

Note that the second command has no .class on the end. This catches everybody once:

java Hello.class
Error: Could not find or load main class Hello.class
Caused by: java.lang.ClassNotFoundException: Hello.class

You pass java a class name, not a file name. It then goes looking for Hello.class itself. The error is oddly worded because the JVM believes you asked for a class called Hello.class, and it is right that no such class exists.

There is also a shortcut, available since Java 11:

java Hello.java

That compiles in memory and runs in one step, leaving no .class file behind. It is excellent for learning and for a single throwaway file, and useless the moment you have two classes. Use it freely in this module.

Every word, in order

public

An access modifier. public means "visible from anywhere". The alternatives — private, protected, and leaving it off — restrict visibility, and module 3 covers them properly.

For main, public is required: the JVM has to be able to call it from outside your class.

class Hello

In Java, code lives inside a class. There are no free-floating functions the way there are in Python or JavaScript. Even a program this small needs a class to put main inside.

And here is the rule that explains the capital H. A public class must be declared in a file with exactly its own name. Put public class Hello in a file called Greet.java and the compiler stops you:

Greet.java:1: error: class Hello is public, should be declared in a file named Hello.java
public class Hello {
       ^
1 error

Unusually strict, and there is a reason: the compiler and the JVM find a class by turning its name into a path. com.riztech.tiffin.Customer lives at com/riztech/tiffin/Customer.java. Without the rule, finding a class would mean searching every file.

One honest footnote, since this course targets Java 21 and you may install 25. In Java 25 a file containing only a main method — no class declaration at all — became legal. It is a genuine improvement for teaching. We are using the full form anyway, because every Java file you will be paid to read has a class declaration in it, and learning the shape that is actually in use matters more than saving two lines.

static

A static method belongs to the class, not to any object made from it.

That is why main must be static, and the reason is a chicken-and-egg problem: main is the first of your code to run, so at that instant no Hello object exists. Something that needed an object could not be called. static means the JVM can call it on the class directly.

Drop the static and the program compiles perfectly — then fails to start:

Error: Main method is not static in class Hello, please define the main method as:
   public static void main(String[] args)

Compiling and running are separate failures. This is the first example in the course of code that is valid Java and still wrong, and it is a distinction worth holding on to. The compiler checks types and syntax. It does not check that you built something the JVM can start.

void

The return type. void means the method returns nothing.

If you need to signal failure to the operating system — the thing a shell script checks — you call System.exit(1) rather than returning a number. 0 means success by convention, anything else means failure.

main

Just a name, but the exact one the JVM looks for. Spell it Main and you get:

Error: Main method not found in class Hello, please define the main method as:
   public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

The JavaFX line is historical noise from an era when desktop Java was expected. Ignore it. Everything before it is the real message.

String[] args

An array of strings: whatever was typed on the command line after the class name. Extend the program to see it:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Namaste, Pune");
        System.out.println("Arguments received: " + args.length);
        for (String arg : args) {
            System.out.println("  " + arg);
        }
    }
}
java Hello Priya 12
Namaste, Pune
Arguments received: 2
  Priya
  12

Two things worth noticing. args is never null — with no arguments it is an empty array, so args.length is 0 and the loop runs zero times. And both arguments are strings: 12 arrives as the text "12", not the number 12. Converting it is Integer.parseInt(args[1]), which is module 2's business.

The name args is convention, not law. String[] whatever works identically.

Printing properly

System.out.println is three things stacked up: the class System, its field out (an output stream connected to your terminal), and that stream's println method.

You have four tools, and knowing all four now saves a lot of clumsy string concatenation later:

public class Bill {
    public static void main(String[] args) {
        String customer = "Priya";
        int tiffins = 26;
        double perTiffin = 82.5;

        System.out.print("Customer: ");
        System.out.println(customer);
        System.out.printf("%d tiffins at Rs %.2f = Rs %.2f%n", tiffins, perTiffin, tiffins * perTiffin);
        System.out.printf("%-12s|%8s|%n", "Item", "Amount");
        System.err.println("This line goes to standard error");
    }
}
Customer: Priya
26 tiffins at Rs 82.50 = Rs 2145.00
Item        |  Amount|
This line goes to standard error
  • print writes without a line break.
  • println adds one.
  • printf formats. Note %n rather than \n — %n emits whatever the platform's line ending is, which matters when your output is read on Windows.
  • System.err is a separate stream for errors, so that a user can redirect normal output to a file and still see the problems. Use it for errors and nothing else.

The format specifiers you will actually use:

Specifier Means Given Produces
%s Any value, as text 1234.5678 1234.5678
%d Whole number 1234 1234
%f Decimal, 6 places by default 1234.5678 1234.567800
%.2f Decimal, rounded to 2 places 1234.5678 1234.57
%,d Thousands separators 1234567 1,234,567
%5d Number right-aligned in 5 columns 42 ···42
%8s Text right-aligned in 8 columns Rs ······Rs
%-8s Text left-aligned in 8 columns Rs Rs······
%b Boolean true true
%n Platform line ending a line break
%% A literal percent sign %

In the padded rows, each · is one real space — shown that way because a web page collapses runs of spaces and you would not see them otherwise.

Those are String.format results. It takes the same format strings as printf but returns the text instead of printing it, and you will use both.

One warning: %d with a double throws at runtime, not at compile time.

java.util.IllegalFormatConversionException: d != java.lang.Double

printf accepts any objects, so the compiler cannot check that your format string matches them. It is the one place in this lesson where Java's type checking does not protect you, and d != java.lang.Double is the message to recognise: "you asked for an integer, you handed me a Double".

Break it on purpose

This is the part that actually teaches. Cause all five of these deliberately. Read each message. Say out loud what it is telling you before you fix it.

Getting good at Java is largely getting fast at reading javac output, and the only way there is having seen the messages often enough that they stop looking like noise.

  1. Delete the semicolon after println(...).
  2. Rename the method from main to Main, then compile and run.
  3. Remove static, then compile and run.
  4. Rename the file to Greet.java, leaving the class as Hello.
  5. Run java Hello.class.

Errors 1 and 4 come from the compiler. Errors 2, 3 and 5 come from the JVM, after a successful compile. Knowing which half of the toolchain is complaining tells you where to look.

Check your work

Why must main be static? Because it runs before any object of your class exists. A non-static method would need an instance to be called on, and there is nothing to create one. Dropping static compiles fine and fails at startup with Main method is not static in class Hello.

Why does java Hello.class fail? java takes a class name, not a file name. It appends .class itself and goes looking for Hello.class.class. The message is Could not find or load main class Hello.class.

Why must the file be called Hello.java? A public class must live in a file named after it, because the compiler and JVM locate classes by mapping the name to a path. The error is explicit: class Hello is public, should be declared in a file named Hello.java.

What is in args when you run java Hello with nothing after it? An empty array — not null. args.length is 0, and a for loop over it runs zero times.

java Hello 12 — is args[0] the number 12? No. It is the string "12". Arguments always arrive as text; converting is Integer.parseInt(args[0]).

Why %n rather than \n in printf? %n produces the platform's line ending. \n is always a single newline character, which can render as one long line in some Windows tools.

Which errors were compile-time and which were runtime? Missing semicolon and wrong file name are compile-time. Main instead of main, missing static, and java Hello.class are all runtime — the code compiled cleanly and the JVM could not start it.

Practice

  1. Type the Hello class in by hand and run it from the terminal. Both commands, javac then java. Then run it again with java Hello.java and check that no .class file appears the second time.

  2. Cause all five errors from the section above, in order, and read each message. Write down, for each, whether javac or java produced it.

  3. Print your own name and city with three arguments. Make java Hello Rizwan Pune 411014 print a line using all three, with the pincode inside a formatted string rather than glued on with +.

  4. Print a tiffin bill with printf. Two columns — item name left-aligned in 15 characters, amount right-aligned in 10 with two decimal places — and a total line under it. Hint: %-15s%10.2f%n. Getting columns to line up is fiddly and worth doing once by hand, because it is how every command-line report you write from here on will be printed.

  5. Break printf on purpose. Pass a double to %d and run it. You get IllegalFormatConversionException at runtime with no compiler warning beforehand. Note where in the output the exception appeared relative to your earlier println lines — that tells you how far the program got.

  6. Read args when there are none. Print args.length with no arguments supplied, and confirm it prints 0 rather than throwing. Then print args[0] with no arguments and read the ArrayIndexOutOfBoundsException carefully — it names the index and the length. Module 7 is about exceptions, but this is the one you will meet first.


That is module one. You have a working JDK, an IDE, and you know what each word of public static void main(String[] args) does and which half of the toolchain complains when it is wrong.

Next module: the language itself — types, var, strings, control flow, and the integer division that quietly produces the wrong answer.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship