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 .
ToolCommandWhat it is for
CompilerjavacSource to bytecode, producing .class files
LauncherjavaRuns classes, jars and single source files
REPLjshellTry an API without creating a project
PackagerjarBundle classes and resources into an archive
Inspectorjdeprscan / jdepsFind deprecated APIs and dependencies
Build toolmvn / gradleResolve libraries, compile, test, package
  • Install the JDK, not just a runtime; javac is missing from a JRE-style install and that failure looks like a broken PATH.
  • 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"
}
AspectMavenGradle
Build filepom.xml, XMLbuild.gradle.kts, Kotlin DSL
ModelDeclarative lifecycle with fixed phasesProgrammable tasks and a dependency graph
Wrappermvnw / mvnw.cmdgradlew / gradlew.bat
Incremental buildsCorrect but slowerFaster, with a build cache
Best suited toUniform large organisations, many modulesGreenfield 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 normal import statement.
  • 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.

Control flow, methods and the modern main Modules, packages and build configuration

Last refreshed 2026-09-18.