Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
4: Compiling and Running with javac and java
I see this happen constantly with new developers: they treat the java command like a Python or Ruby interpreter. They write a file, type java MyProgram.java, and when it doesn't behave exactly how they expect—or when they see a Could not find or load main class error—they assume their code is broken. In reality, their code is fine; their mental model of how Java actually reaches the CPU is what's broken.
The Myth: "java" is a one-step command
If you've played around with modern Java (version 11+), you might have noticed you can actually run a single file using java MyFile.java. This creates the illusion that Java is an interpreted language. But here is where the trap lies: doing this doesn't produce a reusable artifact. If you try to run that same program again, or try to reference it from another class, you'll realize you have nothing to show for it on your disk except the original source code.
In a professional environment, we almost never "run the source." We compile it into bytecode. If you skip the compilation step and try to run a class that hasn't been compiled yet by calling java MyProgram (without the .java extension), the Java Virtual Machine (JVM) will look for a MyProgram.class file, fail to find it, and crash with a cryptic error. It's not looking for your text file; it's looking for the machine-readable version.
The Reality: The two-step dance of javac and java
To understand this, let's use a real scenario. Imagine we're building a TemperatureConverter. You've written your logic to switch between Celsius and Fahrenheit in a file named TemperatureConverter.java.
The first tool you need is javac. This is the Java Compiler. Its only job is to translate your human-readable code into "bytecode"—a highly optimized set of instructions that the JVM understands. When you run this command:
javac TemperatureConverter.java
Nothing seems to happen in the terminal. That's actually a good thing in the world of C-style compilers; no news is good news. But if you look at your folder, a new file has appeared: TemperatureConverter.class. This is the "compiled" version. This is what actually gets shipped to production servers, not your .java files.
Now that we have the bytecode, we use the java command (the launcher) to start the JVM and execute that class. But here is the part that trips people up: you do not include the file extension here.
java TemperatureConverter
I want you to notice the difference. javac takes a file (hence the .java). java takes a class name. If you type java TemperatureConverter.class, the JVM will look for a class literally named "class" inside a package named "TemperatureConverter", and it will fail miserably.
I've spent hours of my career debugging "Class Not Found" errors only to realize I had a typo in the class name or was accidentally including the extension in the run command. It's a rite of passage. Just remember: javac creates the artifact; java breathes life into it.
📋 Practical Task
Debug the TemperatureConverter Execution Workflow
You have been handed a file named TemperatureConverter.java. Your goal is to get the program running on your machine, but you've encountered a series of errors. Follow these steps to fix the workflow:
The Setup:
Create a file named TemperatureConverter.java with the following content:
public class TemperatureConverter {
public static void main(String[] args) {
double celsius = 25.0;
double fahrenheit = (celsius * 9/5) + 32;
System.out.println(celsius + "C is " + fahrenheit + "F");
}
}
The Challenge:
1. Try to run the program using java TemperatureConverter immediately. Observe the ClassNotFoundException or Could not find or load main class error. Explain to yourself why this happened based on the lesson.
2. Use the correct compiler command to generate the bytecode.
3. Run the program using the correct launcher command (remember: no file extensions!).
4. Verify that TemperatureConverter.class exists in your directory and delete the .java file. Try running the program again using the java command. Notice how the program still runs even though the source code is gone—this is the power of the compiled bytecode.
There are no comments for now.