skip to content

What are the limitations of single-file source-code execution, and when should you use a build tool instead?

level: middleimportance: should knowfreq 48%

answer

  1. One file only — no separate compilation
  2. No .class / no JAR produced (in-memory)
  3. Libraries OK via --class-path; your own multi-file isn't
  4. JEP 458 (Java 22) relaxes the multi-file limit
  5. Use Maven/Gradle once you need deps/tests/packaging

basics

~20 s

It runs only one .java file — it can't compile several source files that depend on each other, and it writes no .class output. Use a real build tool (Maven/Gradle) once your project spans multiple files or needs dependencies and packaging.

solid answer

~40 s

JEP 330's single-file mode is deliberately minimal. Its main constraints: it compiles exactly **one** source file, so it can't do *separate compilation* across multiple `.java` files that reference each other; it produces **no `.class` artifact** on disk, so it isn't a build/packaging mechanism; and the named file's classes shadow any same-named compiled classes on the classpath. You can still add libraries via `--class-path` and define multiple classes inside the one file, but the entry point is constrained. So it's perfect for scripts, teaching, prototypes, and reproductions, but the moment you have multiple interdependent source files, dependency management, resources, tests, or a deliverable JAR, you should move to Maven or Gradle (or, for the multi-file gap specifically, the later JEP 458 multi-file source launcher).

go deeper

for a junior

Knows it only handles a single file and produces no .class file, and that bigger projects need a build tool.

for a middle

Can explain 'no separate compilation', classpath usage for libraries, and the in-memory (no artifact) nature; names Maven/Gradle as the next step.

for a senior

Discusses classpath-shadowing semantics, when to graduate to a build tool, and that JEP 458 specifically addresses the multi-file gap.

for a principal

Reasons about the tooling spectrum and governance: why keeping source-mode minimal (not a build system) is a deliberate design boundary, and where script-mode is appropriate vs a risk in production pipelines.

## Recap of the feature Single-file source execution (**JEP 330, Java 11**) lets `java Foo.java` **compile a source file in memory and run it** in one step, skipping the explicit `javac` (compiler) call. This question is about its **boundaries**. ## Limitation 1 — exactly one source file (no separate compilation) *Separate compilation* means compiling several `.java` files that reference one another (e.g. `App.java` uses a class declared in `Service.java`). Single-file mode does **not** do this: it only compiles the file you named on the command line. If `App.java` imports a type that lives in another *source* file, compilation fails because that file is never compiled. Workarounds: - Put **all** your classes inside the **one** file (legal — a `.java` file may declare multiple top-level classes, though only one can be the entry point). - Use ordinary `javac` + `java` for a couple of files. - Use **JEP 458** ("Launch Multi-File Source-Code Programs", finalized in Java 22), which extended the launcher to also compile the *other* source files in the same source tree on demand — this directly relaxes the single-file restriction for source-mode runs. ## Limitation 2 — no compiled artifact Because compilation happens **in memory**, no `.class` file (and certainly no JAR) is written. That's a feature for scripting (nothing to clean up) but means source mode is **not a build system**: you can't hand someone a `.class`/`.jar`, you can't sign or package it, and you re-compile on every run. ## Limitation 3 — classpath shadowing semantics When running in source mode, the classes defined in **your file take precedence** over identically-named classes that might already exist on the classpath. This avoids accidentally running a stale compiled version, but is a subtlety to be aware of if you mix source mode with a populated classpath. ## What still works - **External libraries**: add jars with `--class-path`/`-cp` (or modules with `--module-path`). The single-file restriction is only about compiling *your own* source files, not about using pre-compiled dependencies. - **Language preview features**: `--enable-preview --source <n>` works. - **Multiple classes in one file** and (in newer Java) implicitly declared classes / instance `main`. ## When to reach for a build tool instead Move to **Maven** or **Gradle** (build/dependency tools) when you have any of: - **Multiple interdependent source files** (and you don't want them all in one file, or you're pre-JEP 458). - **Dependency management** beyond a hand-maintained `-cp` (transitive deps, versions, lockfiles). - **Resources, tests, packaging** (JAR/fat-JAR, container images), reproducible builds, CI. - **A shippable deliverable** rather than an ad-hoc run. ## Mental model Think of a spectrum of ceremony: **JShell** (type one expression) → **single-file execution** (run one small program) → **JEP 458 multi-file launch** (run a small multi-file program from source) → **Maven/Gradle** (real builds). Single-file mode sits at the low-ceremony end and is intentionally not trying to be a build system.

  • Your script grew to two interdependent .java files. What changed in newer Java to still run from source?
    JEP 458 (finalized Java 22) added multi-file source launching: the `java` launcher can compile the additional source files in the same tree on demand, lifting the strict one-file limit for source mode.
  • Does single-file mode let you depend on a third-party JAR?
    Yes. The one-file restriction only concerns compiling your own source files. Put the JAR on the classpath with `--class-path`/`-cp` (or use `--module-path`).

saying these in an interview costs you the question

  • Saying it can compile a whole multi-file project as-is (it can't, pre-JEP 458)
  • Claiming it can't use any libraries (it can via --class-path)
  • Treating it as a packaging/build mechanism (no artifact is produced)
  • Forgetting that multiple classes are allowed inside the single file

context