Java runs the enterprise. Banking systems, Android apps, payment processors, and huge swathes of backend infrastructure are written in it. It is verbose by design and stubbornly stable — which is exactly why large organisations keep choosing it, and why Java skills stay in demand decades after launch.
Java powers the Android operating system, the Spring framework behind thousands of microservices, and big-data tools like Hadoop and Kafka. It is not the newest language, but it is the one that large teams bet on when uptime matters more than syntax fashion. When you learn Java, you are learning the language that underpins global finance, telecoms, and logistics.
Compile, then run
This is the biggest mental shift coming from Python or JavaScript. Those languages read your source and run it immediately. Java takes an extra step: a compiler (javac) turns your .java source into bytecode, and the JVM executes that bytecode.
That extra step is why Java catches whole classes of mistakes before your program ever runs. Assign a String to an int and the compiler refuses — you get an error at build time, not a 3 a.m. production crash. The compiler is your first line of defence: it checks types, resolves names, and enforces syntax rules before anything executes.
The bytecode step is also what makes Java portable. You compile Main.java on a Mac, producing Main.class, and that same .class file runs on a Windows server or an Android phone — as long as a JVM exists for that platform. Bytecode is the universal instruction set; the JVM is the abstraction layer. 'Write once, run anywhere' is not a slogan — it is the mechanical reason Java dominates cross-platform deployment.
The JVM does not simply interpret bytecode line by line. A Just-In-Time (JIT) compiler watches which methods run most often and translates them into native machine code while the program is running. Hot loops get faster the longer they execute, which is why a well-tuned Java server can match the speed of natively compiled languages despite the extra compilation step.
flowchart LR S["Main.java (source)"] --> C["javac (compiler)"] C --> B["Main.class (bytecode)"] B --> J["JVM"] J --> O["Program output"] C -.->|type errors caught here| E["Build fails early"] style C fill:#c2410c,color:#fff style J fill:#c2410c,color:#fff
flowchart LR BC["Main.class (bytecode)"] --> CL["Classloader"] CL --> V["Bytecode Verifier"] V --> JIT["JIT Compiler"] JIT --> MC["Native machine code"] MC --> OUT["Program output"] style CL fill:#c2410c,color:#fff style JIT fill:#c2410c,color:#fff
Your first Java program
Every Java program lives inside a class, and execution starts at a method called main. Read this line by line — System.out.println prints one line to the console.
Notice the filename must match the public class name. Because the class is public class Main, the file must be named Main.java. Change one without the other and the compiler complains. That rule is strict, but it makes navigation predictable: a class called Invoice lives in Invoice.java, period.
Inside main, the parameter String[] args holds any command-line arguments you pass when starting the program. If you run java Main Ada 2026, then args[0] is "Ada" and args[1] is "2026". Most programs ignore args at first, but every serious application uses them for configuration, file paths, or flags.
public class Main {
public static void main(String[] args) {
String name = "Ada";
int year = 2026;
System.out.println("Hello, " + name + "!");
System.out.println("Java still runs the world in " + year + ".");
}
}
Anatomy of a method
The main method header is dense, but every piece has a purpose:
public— the JVM must be able to call it from outside the class.static— the JVM calls it without creating an object first.void— it returns nothing to the caller (the JVM does not expect a value).main— the exact name the JVM searches for.String[] args— an array of command-line arguments.
Omit public, misspell main, or change the parameter type, and the program compiles but refuses to run. The JVM simply will not find an entry point. That rigidity is frustrating at first, but it makes every Java program predictable: open any project, find public static void main, and you know where execution begins.
flowchart LR
subgraph "main signature"
A["public"] --> B["static"]
B --> C["void"]
C --> D["main(String[] args)"]
end
D --> E["JVM entry point"]
style D fill:#c2410c,color:#fff
public class Main {
public static void main(String[] args) {
System.out.println("Arguments: " + args.length);
if (args.length > 0) {
System.out.println("First: " + args[0]);
}
}
}
Case sensitivity and the exactness trap
Java is case-sensitive everywhere: Main and main are different names. The class is Main, the method is main, and confusing them produces errors that look cryptic to beginners. A file named main.java containing public class Main fails to compile because the filename does not match the public class name. Similarly, Public class Main fails because Public is not the keyword public.
This exactness feels like bureaucracy, but it is what lets the compiler and the JVM agree on where everything lives. Once you accept the rule, you can open any Java project anywhere in the world and know exactly how the files map to classes.
public class Main {
public static void greet(String name) {
System.out.println("Hello, " + name + "!");
}
public static void main(String[] args) {
greet("Ada");
greet("Java");
}
}
Reading compiler errors
Compilation errors are your friend, not your enemy. When javac rejects your code, it prints a file name, a line number, and a message such as cannot find symbol. That precision is possible because the compiler has already built a full model of your program. Read the error bottom-up: the last line usually tells you what is wrong, and the lines above show where the compiler was looking. Fixing compile errors quickly is a skill in its own right, and every senior engineer has spent thousands of hours doing exactly that.
What does this program print? Read it carefully and type the exact output (two lines).
public class Main {
public static void main(String[] args) {
String name = "Ada";
int year = 2026;
System.out.println("Hello, " + name + "!");
System.out.println("Java still runs the world in " + year + ".");
}
}
+joins strings together; theintis converted to text automatically.printlnprints one line each — so there are two lines of output.
What does javac produce from Main.java?
javac compiles source to platform-independent bytecode (.class). The JVM executes that bytecode — which is what lets the same Java run anywhere there's a JVM.
What does this program print? Read it carefully and type the exact output (two lines).
public class Main {
public static void greet(String name) {
System.out.println("Hello, " + name + "!");
}
public static void main(String[] args) {
greet("Ada");
greet("Java");
}
}
greetis called twice frommain, once with"Ada"and once with"Java".Each call prints one line.
What does this program print when run with no command-line arguments? Read it carefully and type the exact output (one line).
public class Main {
public static void main(String[] args) {
System.out.println("Arguments: " + args.length);
if (args.length > 0) {
System.out.println("First: " + args[0]);
}
}
}
With no arguments,
args.lengthis0.The
ifcondition isfalse, so the secondprintlndoes not run.
Why can a .class file compiled on macOS run on a Linux server?
Bytecode is platform-independent. The JVM on each platform translates it to native machine code at runtime, so the same .class file runs anywhere a JVM is installed.
Recap
- Java is statically typed and compiled: the compiler catches type errors before the program runs.
javacturns.javasource into.classbytecode; the JVM executes that bytecode on any platform with a JVM.- Every program starts at
public static void main(String[] args). - The file name must match the public class name exactly, and Java is case-sensitive everywhere.
String[] argscarries command-line arguments into your program.- Compilation errors give precise file and line information — learn to read them carefully.
- Reading code and predicting its output is the skill this course builds — every sample is real, compiling Java.
Next you will meet variables and types, and discover how Java's strict type system keeps bugs out of production.