How do I Organize Multiple Methods in a Compact Source File?

Java 25 makes it easier than ever to write small, focused programs without ceremony. Thanks to JEP 512: Compact Source Files and Instance Main Methods (finalized in Java 25), you can skip the enclosing class declaration entirely and still define multiple methods and fields in a single source file. This is perfect for scripts, learning exercises, and quick utilities.

Let me walk you through the best practices for organizing methods in these compact files.


1. The Basic Structure

A compact source file has an implicit top-level class. You just write your main method (instance-style, no static required) and add helper methods around it:

void main() {
    println("Welcome!");
    greet("Alice");
    println("Sum = " + add(3, 4));
}

void greet(String name) {
    println("Hello, " + name + "!");
}

int add(int a, int b) {
    return a + b;
}

No public class Foo { ... } wrapper is needed. The compiler generates it for you.


2. Put main First (or Make It Easy to Find)

For readability, keep the entry point at the top of the file so a reader immediately sees the program’s flow:

void main() {
    var user = askName();
    var total = computeTotal(10, 20, 30);
    printReport(user, total);
}

// --- helpers below ---

String askName() {
    return "Guest";
}

int computeTotal(int... values) {
    int sum = 0;
    for (int v : values) sum += v;
    return sum;
}

void printReport(String user, int total) {
    println("User : " + user);
    println("Total: " + total);
}

This mirrors how many scripting languages read: entry point first, details after.


3. Group Related Methods Together

When your file grows, cluster methods by responsibility and separate the groups with comment banners:

void main() {
    var nums = List.of(1, 2, 3, 4, 5);
    println("Sum      = " + sum(nums));
    println("Average  = " + average(nums));
    println("Uppercase: " + shout("hello"));
}

// ---------- Math helpers ----------

int sum(List<Integer> xs) {
    return xs.stream().mapToInt(Integer::intValue).sum();
}

double average(List<Integer> xs) {
    return xs.stream().mapToInt(Integer::intValue).average().orElse(0);
}

// ---------- String helpers ----------

String shout(String s) {
    return s.toUpperCase() + "!";
}

If a group becomes large, that is a strong signal it should be extracted into its own class or file.


4. Use Instance Fields for Shared State

Compact files support instance fields, so you don’t need to pass configuration through every method call:

final String appName = "DemoApp";
final int maxRetries = 3;

void main() {
    banner();
    run();
}

void banner() {
    println("=== " + appName + " ===");
}

void run() {
    for (int i = 1; i <= maxRetries; i++) {
        println("Attempt " + i);
    }
}

Prefer final fields to keep the file predictable and easy to reason about.


5. Leverage the Auto-Imported java.base and IO Methods

Java 25 auto-imports common utilities and gives you top-level print, println, and readln (from java.lang.IO). This keeps helper methods short:

void main() {
    var name = readln("Your name: ");
    println(greeting(name));
}

String greeting(String name) {
    return "Hello, " + (name.isBlank() ? "stranger" : name) + "!";
}

No import statements, no System.out.println — the file stays compact.


6. Keep Methods Small and Single-Purpose

Because there is no class boundary to hide behind, discipline matters more. Follow these guidelines:

Guideline Why it matters in a compact file
One responsibility per method Compensates for the flat structure
Short method names, descriptive The file reads top-to-bottom like a script
Prefer pure functions Easier to reason about without a class scope
Extract when > ~15 lines Prevents the file from becoming a wall of code

7. Order Methods by “Newspaper Style”

Arrange methods so the reader moves from high-level to low-level, like a newspaper article:

void main() {           // headline: what the program does
    processOrder();
}

void processOrder() {   // section: main steps
    validate();
    charge();
    ship();
}

void validate() { /* ... */ }   // details
void charge()   { /* ... */ }
void ship()     { /* ... */ }

Readers rarely need to jump around — they simply scroll down for more detail.


8. When to Stop Using a Compact File

Compact source files shine for small, self-contained programs. Migrate to a regular class (or multiple classes) when you notice:

  • Multiple unrelated groups of methods
  • Need for multiple types (records, enums beyond simple helpers)
  • Reuse from other files
  • Unit tests targeting individual methods

You can promote a compact file by simply wrapping everything in public class Name { ... } and adding public static void main(String[] args) — the migration is mechanical.


Complete Example

Here is a compact file that puts all the tips together:

final String title = "Tip Calculator";

void main() {
    banner();
    double bill = 84.50;
    double tipPct = 0.18;

    double tip = tipAmount(bill, tipPct);
    double total = bill + tip;

    printLine("Bill",  bill);
    printLine("Tip",   tip);
    printLine("Total", total);
}

// ---------- domain logic ----------

double tipAmount(double bill, double pct) {
    return round2(bill * pct);
}

double round2(double v) {
    return Math.round(v * 100.0) / 100.0;
}

// ---------- output helpers ----------

void banner() {
    println("=== " + title + " ===");
}

void printLine(String label, double value) {
    println(String.format("%-6s: %8.2f", label, value));
}

Run it directly with:

java TipCalculator.java

Summary

  • Put main first, helpers below.
  • Group related methods and separate groups with comment banners.
  • Use instance fields for shared, mostly-final state.
  • Rely on auto-imports and top-level IO methods to stay concise.
  • Follow newspaper order — general to specific.
  • Graduate to a regular class once the file grows beyond a single concern.

Compact source files let you write real, multi-method programs with almost zero boilerplate — as long as you keep the file focused and well-organized.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.