Setting up a modern Java toolchain
Install an LTS JDK, learn what javac and java really do, lay out a project, and pick between Maven and Gradle.
One JDK, a handful of commands
A single LTS JDK installation is enough to compile, run, experiment and package. Distributions differ in licensing and bundled tools rather than in the language, so pick one (Temurin, Corretto, Oracle, Microsoft) and keep the version consistent across your team and CI.
java -version # the launcher and the runtime
javac -version # the compiler that ships with a JDK, not a JRE
java Hello.java # single-file source: compile and run in one step
jshell # interactive REPL
javadoc -d docs src/main/java/com/example/*.java
jar --create --file app.jar -C out .| Tool | Command | What it is for |
|---|---|---|
| Compiler | javac | Source to bytecode, producing .class files |
| Launcher | java | Runs classes, jars and single source files |
| REPL | jshell | Try an API without creating a project |
| Packager | jar | Bundle classes and resources into an archive |
| Inspector | jdeprscan / jdeps | Find deprecated APIs and dependencies |
| Build tool | mvn / gradle | Resolve libraries, compile, test, package |
- Install the JDK, not just a runtime;
javacis missing from a JRE-style install and that failure looks like a brokenPATH. - Pin the version with a manager (
sdkman,asdf, Homebrew, winget) so every machine resolves the same one. - The release target matters more than the JDK you build with: set it to the oldest version you deploy to.
Project layout and build tools
Both mainstream build tools expect the same conventional layout: src/main/java for code, src/main/resources for files loaded from the classpath, and src/test/java for tests. Keeping to it means no configuration at all for the basic case.
<!-- pom.xml — Maven: a declarative description of the build -->
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>orders</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.release>25</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>// build.gradle.kts — Gradle: a programmable build script
plugins {
application
}
java {
toolchain { languageVersion = JavaLanguageVersion.of(25) }
}
repositories { mavenCentral() }
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
}
application {
mainClass = "com.example.orders.Main"
}| Aspect | Maven | Gradle |
|---|---|---|
| Build file | pom.xml, XML | build.gradle.kts, Kotlin DSL |
| Model | Declarative lifecycle with fixed phases | Programmable tasks and a dependency graph |
| Wrapper | mvnw / mvnw.cmd | gradlew / gradlew.bat |
| Incremental builds | Correct but slower | Faster, with a build cache |
| Best suited to | Uniform large organisations, many modules | Greenfield projects and fast CI |
💡
Commit the wrapper. Running
./mvnw verify or ./gradlew build guarantees everyone, including CI, uses the same build-tool version instead of whatever happens to be installed.jshell and the IDE
jshell> var names = List.of("Ada", "Grace")
names ==> [Ada, Grace]
jshell> names.stream().map(String::toUpperCase).toList()
$2 ==> [ADA, GRACE]
jshell> /vars # every variable defined so far
jshell> /methods # and every method
jshell> /reset # clear state
jshell> /exit- jshell compiles each snippet immediately, which makes it the fastest way to check a method signature or an unfamiliar API.
- Imports are automatic for
java.base; add others with a normalimportstatement. - Configure the project SDK in the IDE to the same LTS you deploy on, and let the build tool own the compiler settings rather than the IDE.
- IntelliJ IDEA and VS Code with the Java Extension Pack both run the debugger and the profiler; either is fine.
- Keep one command that a newcomer can run to build and test the whole project, and put it in the README.
FAQ
Maven or Gradle for a new project?
Gradle if you want a fast, scriptable build and are comfortable in Kotlin or Groovy; Maven if you value a rigid, universally understood structure and your organisation already runs it. Both are production-grade, and switching later is a real cost.
Should I use the newest JDK even if I deploy on an older one?
You can build with a newer JDK and target an older release through the release flag, but the extra language features will not be available. It is usually simpler to develop on the oldest LTS you must support.
Related
Control flow, methods and the modern main Modules, packages and build configuration
Last refreshed 2026-09-18.