A Java program is a file that contains classes, and a class is a container for methods. The shortest program that does anything is three lines of code, but understanding why those three lines are shaped that way is the difference between copying a tutorial and actually being able to write the next program yourself.
What does the smallest complete program look like?
Here is a program that prints a line. Save it as Greeting.java — the file name matters, and the next section explains why.
public class Greeting {
public static void main(String[] args) {
System.out.println("Hello from Java");
}
}
Four parts carry all the weight. public class Greeting declares a class and gives it a name. public static void main is the entry point the launcher looks for. String[] args is where command-line arguments arrive. System.out.println(...) writes a line to standard output.
Compile it and run it, and you will see the line you printed.
javac Greeting.java
java Greeting
The first command produces a Greeting.class file — that is the bytecode. The second command starts the runtime, which loads the class, finds main, and calls it. Two separate steps, two separate artifacts: source becomes bytecode, and the bytecode runs.
Why must the file name match the class name?
Java resolves the public class by looking for a file with the matching name, including its capitalisation. Put public class Greeting in a file called greeting.java and the compiler tells you so:
Greeting.java:1: error: class Greeting is public, should be declared in a file named Greeting.java
The rule exists so a reader — and the compiler — can always find the source for a class by name, without scanning every file in a directory. A file may contain several classes, but only one of them may be public, and that one forces the file name.
What does the main signature actually say?
Break the signature into pieces and each modifier earns its place.
public static void main(String[] args) {
// 1. public : the runtime may call this from outside the class
// 2. static : it belongs to the class, not to an instance
// 3. void : it returns no value
// 4. args : an array of the command-line arguments
int width = 20;
String banner = "--------------------";
System.out.println(banner);
System.out.println("value: " + width);
}
Static matters because the launcher has no object to call the method on — it has only the class. void matters because the runtime does not wait for a result; your program ends when main returns. The args array is the hand-off point for input, and it is worth using early so that arguments feel like a normal part of the language rather than a mystery.
# pass two arguments to the program
java Greeting 42 hello
Inside main, args[0] is the first argument, args[1] the second, and args.length tells you how many arrived. Arguments always arrive as text, so any number you pass is a String until you convert it.
How do you print more than one thing?
System.out.println accepts a single value, and the + operator glues values into a string. The print variant omits the newline, which is what you want when you are building a line piece by piece.
public class Report {
public static void main(String[] args) {
String product = "Notebook";
int quantity = 3;
double price = 4.50;
System.out.println("Item: " + product);
System.out.println("Total: " + (quantity * price));
System.out.print("Loading");
System.out.print(".");
System.out.println(" done");
}
}
Note the parentheses around quantity * price. Without them, + would glue the number to the text first and the arithmetic would never happen — a small trap that catches everyone once, because the program still compiles.
What do the first errors look like?
Two mistakes come up constantly. A missing semicolon produces a message that points at the next line, because the compiler only knows the statement ended when it finds the semicolon. A misspelled class name produces "cannot find symbol" and lists the symbol it wanted.
Greeting.java:4: error: ';' expected
System.out.println("Hello from Java")
^
Read the error from the bottom up: the caret marks the exact position, the line number tells you where to look, and the file name tells you which file. The message text at the top is the least useful part, so do not start there.
What are the other parts of a class?
A class is more than a name and a method. The pieces you will use constantly are fields (the state a class carries), constructors (how an object is created), and methods that operate on that state. A program that models something real tends to have all three, and keeping them ordered in that familiar way makes the code predictable to read.
public class Rectangle {
private final double width;
private final double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double area() {
return width * height;
}
public double perimeter() {
return 2 * (width + height);
}
public static void main(String[] args) {
Rectangle sheet = new Rectangle(21.0, 29.7);
System.out.printf("Area: %.2f%n", sheet.area());
System.out.printf("Perimeter: %.2f%n", sheet.perimeter());
}
}
The shape of this class is the shape of most Java you will write: state as fields, construction in a constructor, behaviour as methods, and a small main that demonstrates the rest. Note that width and height are declared private final — the class owns its data and does not let callers change it behind its back. That is not ceremony; it is what makes the object trustworthy to the rest of the program.
Which names are worth arguing about?
Java has conventions, and following them saves every reader a bit of decoding. Classes are PascalCase. Methods, parameters and variables are camelCase. Constants are UPPER_SNAKE_CASE. A class that represents a single record is often a noun, and its methods are verbs — Rectangle has area(), not computeArea(), because the class name already says what is being computed.
These are conventions rather than rules, and the compiler will not object to anything else. But code that follows them reads as if its author already knew what the code was going to do, and that impression is worth a lot when you return to a file six months later.
Quick reference
- File name must match the
publicclass name, capitalisation included. javac File.javacompiles to bytecode;java ClassNameruns it.mainispublic static void main(String[] args)— the launcher calls it with no instance.- Command-line arguments arrive as strings in
args. - Parentheses matter around arithmetic inside string concatenation.
- Read errors from the caret outwards, not from the top of the message.
Try it yourself: write a class called Profile that prints a name, a role and a joined year on three separate lines, compile and run it. Then change the class name to profile while leaving the file name alone, compile again, and read the error carefully enough to explain why the compiler cares about the difference between the two.