Before you write any code, it helps to understand what actually builds and runs that code. In Java there is a small set of tools around the language itself, and nothing works without them. Let's go through them in order — from what you install on your machine to the build tools that pull in dependencies for you.
JDK, JRE and JVM — who is who
Three acronyms that get confused most often. Let's sort out what's inside each.
JVM (Java Virtual Machine) is the virtual machine. It's the program that executes compiled Java code. You write .java, the compiler turns it into bytecode (.class), and the JVM runs that bytecode. The JVM is exactly what gives Java its famous "write once, run anywhere": the bytecode is the same everywhere, and there is a dedicated JVM for each operating system.
JRE (Java Runtime Environment) is the runtime environment. It's the JVM plus the standard libraries (collections, file and network handling, and so on). This set is enough to run finished Java programs, but not enough to compile them.
JDK (Java Development Kit) is the developer's kit. It's the JRE plus development tools: the javac compiler, a debugger, and more. For development you need exactly the JDK.
A short formula: JDK = JRE + development tools, JRE = JVM + libraries.
In practice, these days almost no one installs a standalone JRE — you download a JDK (for example, a Temurin, Liberica, or Amazon Corretto build) and work with it.
Compiling and running by hand
To get a feel for what happens under the hood of build tools, it's worth building a program by hand at least once.
Suppose you have a file Hello.java:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, Java!");
}
}
Compile it with the javac compiler — it creates Hello.class with the bytecode:
javac Hello.java
Run it with the java command (the class name, without the .class extension):
java Hello
In Java 21 a simple case can be run without a separate compilation step at all — java Hello.java compiles and runs it in one go. That's handy for experiments, but real projects are still built the full way.
classpath — where to look for classes
As soon as you have more than one class and some third-party libraries appear, the JVM needs to be told where to find them. That's what the classpath is for — a list of folders and archives that contain .class files.
# run a class, telling the JVM to look for classes in the out folder and in the lib/some.jar library
java -cp out:lib/some.jar Hello
The classpath separator depends on the system: a colon : on Linux and macOS, a semicolon ; on Windows. You rarely assemble a classpath by hand — usually the build tool does it for you, and understanding it is mainly useful for diagnosing errors like ClassNotFoundException (the class wasn't found on the classpath).
What is a jar
Scattering hundreds of .class files around is inconvenient. A jar (Java ARchive) is an ordinary zip archive containing .class files and accompanying metadata. One file instead of a pile of classes: it's easy to share, add as a dependency, and run.
If a jar declares an entry point (a main class), you can run it directly:
java -jar app.jar
The libraries you add to a project also arrive as jar files. Your own project, at the end of a build, most often turns into a jar as well.
Maven and Gradle — why you need build tools
While your project is a single file, javac and java are enough. But a real application consists of dozens of your own classes and depends on third-party libraries that have their own dependencies. Downloading all of that by hand, setting up the classpath, and keeping track of versions is painful. Build tools take this work on: they download dependencies, compile the code, run the tests, and assemble the final jar.
In the Java world there are two main build tools — Maven and Gradle. Both do the same thing; they differ in how the project is described.
Dependency coordinates. Any library in Java is uniquely described by three parts: groupId (who published it, usually in reverse-domain style), artifactId (which library it is), and version (the version). This triple is its coordinates. Using the coordinates, the build tool finds and downloads the right jar from a repository (Maven Central by default).
Maven describes a project in a pom.xml file (XML). A dependency looks like this:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.1-jre</version>
</dependency>
Gradle describes a project in build.gradle (Groovy) or build.gradle.kts (Kotlin). The same dependency — one line by coordinates:
dependencies {
implementation("com.google.guava:guava:33.2.1-jre")
}
The build command is short too: mvn package for Maven, gradle build for Gradle (or ./gradlew build via the wrapper, which installs the right Gradle version itself).
Basic project structure
By default Maven and Gradle expect the same folder layout — and almost all ecosystem code follows it:
my-app/
├── pom.xml # or build.gradle(.kts)
└── src/
├── main/
│ ├── java/ # application source code
│ └── resources/ # config files, templates, etc.
└── test/
├── java/ # test code
└── resources/ # test data
The main rule: production code goes in src/main, tests in src/test. The build tool knows these paths and doesn't require you to configure them. The build output lands in a separate folder (target/ for Maven, build/ for Gradle), which is not committed to version control.
Managing your JDK version
The JDK is released regularly, and a single machine often needs several versions: one project on Java 17, another on Java 21. Version managers help you keep them and switch between them.
- SDKMAN! is a popular tool for Linux and macOS. It installs and switches JDKs (and Gradle/Maven themselves) with a single command:
sdk install java 21.0.3-tem, thensdk use java 21.0.3-tem. - The default version is set by the
JAVA_HOMEenvironment variable — the path to the JDK you want. Thejava -versionandjavac -versioncommands show which version is currently active.
It's worth knowing about LTS versions (Long-Term Support) separately — these are releases with long support (17, 21, …). For production projects people usually pick exactly these: security updates keep coming for them longer.
In short
- The JVM executes bytecode, JRE = JVM + libraries (running only), JDK = JRE + tools (you need the JDK for development).
javac Hello.javacompiles the source into.classbytecode,java Helloruns it.- The classpath is a list of paths where the JVM looks for classes; a
ClassNotFoundExceptionmeans the class wasn't found there. - A jar is a zip archive of classes; a finished application is run as
java -jar app.jar. - Maven (
pom.xml) and Gradle (build.gradle) download dependencies by their coordinatesgroupId:artifactId:versionand build the project. - The standard layout is the same: code in
src/main/java, tests insrc/test/java. - It's convenient to keep several JDK versions on a machine via SDKMAN!; for work you pick LTS versions.
What to read next
- Syntax and data types — what the code you compile is actually made of.
- Exceptions — how Java reports errors at runtime.
- OOP in Java — classes, objects, and how programs are built from them.