Java 11 Running Java Files Directly

1. Introduction

For over 20 years, running a Java program meant two steps: compile it, then run it. Even a simple “Hello, World!” required two commands in the terminal. Want to test a quick idea? Open an IDE, create a project, set up a package, write a class, compile, and then run. Compared to languages like Python or JavaScript where you just type python script.py or node script.js, Java felt heavy even for the smallest tasks.

Java 11 changed that. With JEP 330, you can now run a single Java source file directly without compiling it first. One command. No .class files. No project setup.

The old workflow (before Java 11):

// Step 1: Write the file (HelloWorld.java)
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}
## Step 2: Compile it
javac HelloWorld.java

## Step 3: Run the compiled class
java HelloWorld

## Output: Hello, World!

The new workflow (Java 11+):

## One step: Run the source file directly
java HelloWorld.java

## Output: Hello, World!

That is it. One command. No javac. No .class file created on disk. The JVM compiles the source code in memory and executes it immediately.

Think of it like the difference between writing a formal letter (old way — draft, print, mail) versus sending a text message (new way — type and send). Both communicate, but one has zero ceremony for quick messages.

Why this matters:

  • Scripting — Java can now compete with Python/Bash for quick automation scripts
  • Learning — beginners can run code without understanding compilation, classpaths, or IDEs
  • Prototyping — test an idea in 10 seconds instead of 2 minutes
  • DevOps — write utility scripts in Java instead of switching to another language
  • Unix shebang support — Java files can be made directly executable on Linux/macOS

2. How Single-File Execution Works

When you run java HelloWorld.java, the JVM detects that the argument ends with .java (a source file, not a class name). It then:

  1. Reads the entire source file into memory
  2. Compiles it in memory using the Java compiler (no .class file is written to disk)
  3. Loads the compiled bytecode into the JVM
  4. Finds the main method in the first class declared in the file
  5. Executes the main method

Key detail: The main method must be in the first class in the file. If your file has multiple classes, the first one must contain main.

// File: Demo.java
// The FIRST class must have the main method

public class Demo {
    public static void main(String[] args) {
        Helper helper = new Helper();
        helper.greet("Java 11");
    }
}

// Additional classes are allowed in the same file
class Helper {
    void greet(String name) {
        System.out.println("Hello from " + name + "!");
    }
}

// Run: java Demo.java
// Output: Hello from Java 11!

What happens behind the scenes:

Step Traditional (javac + java) Single-File (java only)
Source file Read from disk Read from disk
Compilation javac writes .class to disk Compiled in memory (no disk I/O)
Class loading JVM loads .class from disk JVM loads bytecode from memory
Execution Runs main in specified class Runs main in first class
Artifacts .class files remain on disk Nothing written to disk
Speed Slightly faster (pre-compiled) Adds compile time on each run

2.1 The Source File is Not a Class Name

Pay close attention to the difference between these two commands:

## This runs a COMPILED class named HelloWorld (looks for HelloWorld.class)
java HelloWorld

## This runs a SOURCE FILE named HelloWorld.java (compiles in memory first)
java HelloWorld.java

The .java extension is what tells the JVM to use single-file execution mode. Without it, the JVM assumes you are specifying a class name and looks for a compiled .class file.

3. Basic Examples

3.1 Simple Program

// File: Greeting.java
public class Greeting {
    public static void main(String[] args) {
        String message = "Welcome to Java 11 single-file execution!";
        System.out.println(message);
        System.out.println("Java version: " + System.getProperty("java.version"));
        System.out.println("OS: " + System.getProperty("os.name"));
    }
}

// Run: java Greeting.java
// Output:
// Welcome to Java 11 single-file execution!
// Java version: 11.0.2
// OS: Mac OS X

3.2 With Command-Line Arguments

Command-line arguments work exactly like they do with compiled classes. Arguments after the filename are passed to main(String[] args):

// File: Greeter.java
public class Greeter {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Usage: java Greeter.java  [...]");
            System.exit(1);
        }

        for (String name : args) {
            System.out.println("Hello, " + name + "!");
        }

        System.out.println("Greeted " + args.length + " people.");
    }
}

// Run: java Greeter.java Alice Bob Charlie
// Output:
// Hello, Alice!
// Hello, Bob!
// Hello, Charlie!
// Greeted 3 people.

3.3 Reading User Input

// File: Calculator.java
import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Enter first number: ");
        double a = scanner.nextDouble();

        System.out.print("Enter second number: ");
        double b = scanner.nextDouble();

        System.out.print("Enter operator (+, -, *, /): ");
        String op = scanner.next();

        double result;
        switch (op) {
            case "+": result = a + b; break;
            case "-": result = a - b; break;
            case "*": result = a * b; break;
            case "/":
                if (b == 0) {
                    System.out.println("Error: Division by zero");
                    return;
                }
                result = a / b;
                break;
            default:
                System.out.println("Error: Unknown operator '" + op + "'");
                return;
        }

        System.out.printf("%.2f %s %.2f = %.2f%n", a, op, b, result);
    }
}

// Run: java Calculator.java
// Enter first number: 15
// Enter second number: 4
// Enter operator (+, -, *, /): *
// 15.00 * 4.00 = 60.00

3.4 Using Standard Library Classes

You can use any class from the Java standard library. Just import it as usual:

// File: DateInfo.java
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.DayOfWeek;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class DateInfo {
    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter =
            DateTimeFormatter.ofPattern("EEEE, MMMM d, yyyy 'at' h:mm a");

        System.out.println("Current time: " + now.format(formatter));
        System.out.println("Day of year: " + now.getDayOfYear());
        System.out.println("Week of year: " +
            now.getDayOfYear() / 7 + 1);

        // Days until weekend
        DayOfWeek today = now.getDayOfWeek();
        int daysUntilSaturday = (DayOfWeek.SATURDAY.getValue()
            - today.getValue() + 7) % 7;
        System.out.println("Days until Saturday: " +
            (daysUntilSaturday == 0 ? "It's Saturday!" : daysUntilSaturday));

        // Quick stream example
        Map> evenOdd = IntStream.rangeClosed(1, 20)
            .boxed()
            .collect(Collectors.partitioningBy(n -> n % 2 == 0));
        System.out.println("Even numbers (1-20): " + evenOdd.get(true));
        System.out.println("Odd numbers  (1-20): " + evenOdd.get(false));
    }
}

// Run: java DateInfo.java
// Output:
// Current time: Friday, February 28, 2026 at 3:42 PM
// Day of year: 59
// Week of year: 9
// Days until Saturday: 1
// Even numbers (1-20): [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
// Odd numbers  (1-20): [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

4. Shebang Scripts

On Unix-like systems (Linux, macOS), you can make Java source files directly executable using a shebang line (#!). This means you can run a Java file just like a shell script or Python script — by typing its name, without even writing java in front of it.

4.1 Creating a Shebang Java Script

#!/usr/bin/java --source 11

// File: sysinfo (no .java extension!)
// This file is executable directly on Unix systems

public class SysInfo {
    public static void main(String[] args) {
        System.out.println("=== System Information ===");
        System.out.println("OS:        " + System.getProperty("os.name")
            + " " + System.getProperty("os.version"));
        System.out.println("Arch:      " + System.getProperty("os.arch"));
        System.out.println("Java:      " + System.getProperty("java.version"));
        System.out.println("JVM:       " + System.getProperty("java.vm.name"));
        System.out.println("User:      " + System.getProperty("user.name"));
        System.out.println("Home:      " + System.getProperty("user.home"));
        System.out.println("Directory: " + System.getProperty("user.dir"));

        Runtime runtime = Runtime.getRuntime();
        long maxMem = runtime.maxMemory() / (1024 * 1024);
        long totalMem = runtime.totalMemory() / (1024 * 1024);
        long freeMem = runtime.freeMemory() / (1024 * 1024);
        System.out.println("Max Memory:   " + maxMem + " MB");
        System.out.println("Total Memory: " + totalMem + " MB");
        System.out.println("Free Memory:  " + freeMem + " MB");
        System.out.println("Processors:   " + runtime.availableProcessors());
    }
}

To make it executable:

## Make the file executable
chmod +x sysinfo

## Run it directly (no 'java' command needed!)
./sysinfo

## Output:
## === System Information ===
## OS:        Linux 5.15.0
## Arch:      amd64
## Java:      11.0.2
## JVM:       OpenJDK 64-Bit Server VM
## User:      developer
## Home:      /home/developer
## Directory: /home/developer/scripts
## Max Memory:   3641 MB
## Total Memory: 245 MB
## Free Memory:  239 MB
## Processors:   8

Shebang rules:

  • The shebang line must be the very first line of the file
  • Use #!/usr/bin/java --source 11 (specify the source version)
  • The file should not have a .java extension — name it like a script (e.g., sysinfo, deploy, cleanup)
  • The Java compiler ignores the shebang line during compilation
  • This only works on Unix-like systems (Linux, macOS), not Windows
  • You can also use #!/usr/bin/env java --source 11 for portability (uses the java from PATH)

4.2 Shebang with Arguments

#!/usr/bin/java --source 11

// File: hello (executable shebang script)

public class Hello {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Hello, World!");
        } else {
            System.out.println("Hello, " + String.join(" and ", args) + "!");
        }
    }
}
chmod +x hello
./hello
## Output: Hello, World!

./hello Alice Bob
## Output: Hello, Alice and Bob!

5. Rules and Limitations

Single-file execution is powerful but has clear boundaries. Understanding these limitations helps you know when to use it and when a full project setup is the right choice.

Rule Detail
Single source file only You cannot reference classes in other .java files. All code must be in one file.
Must have a main method The first class in the file must have public static void main(String[] args).
No external dependencies You cannot use --classpath to add JARs. Only the Java standard library is available.
No package statement needed The file runs in the unnamed (default) package. You can include a package statement, but it is ignored.
File name does not matter Unlike compiled Java, the filename does not need to match the class name.
Compiled every time No caching — the file is recompiled on every execution. This adds startup overhead.
Multiple classes allowed You can define multiple classes in one file. The first one must have main.
Source version Use --source N flag to specify the Java language version to compile against.

5.1 Demonstrating the Rules

// File: RulesDemo.java
// The filename does NOT need to match the class name for single-file execution
// (But it must match for traditional javac compilation)

// No package statement needed (it would be ignored anyway)

import java.util.List;
import java.util.stream.Collectors;

// First class MUST have main
public class RulesDemo {
    public static void main(String[] args) {
        // Using a helper class defined later in this file -- works fine
        MathHelper math = new MathHelper();
        System.out.println("Factorial of 10: " + math.factorial(10));
        System.out.println("Is 17 prime? " + math.isPrime(17));
        System.out.println("Is 18 prime? " + math.isPrime(18));

        // Using another helper class from this same file
        StringHelper strings = new StringHelper();
        System.out.println("Reversed: " + strings.reverse("Java 11"));
        System.out.println("Palindrome 'racecar': "
            + strings.isPalindrome("racecar"));
        System.out.println("Palindrome 'hello': "
            + strings.isPalindrome("hello"));

        // Using Java standard library -- all of it is available
        List primes = List.of(2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
            .stream()
            .filter(n -> n > 10)
            .collect(Collectors.toList());
        System.out.println("Primes > 10: " + primes);
    }
}

// Additional classes in the same file -- no problem
class MathHelper {
    long factorial(int n) {
        long result = 1;
        for (int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }

    boolean isPrime(int n) {
        if (n < 2) return false;
        for (int i = 2; i * i <= n; i++) {
            if (n % i == 0) return false;
        }
        return true;
    }
}

class StringHelper {
    String reverse(String s) {
        return new StringBuilder(s).reverse().toString();
    }

    boolean isPalindrome(String s) {
        String clean = s.toLowerCase().replaceAll("[^a-z0-9]", "");
        return clean.equals(new StringBuilder(clean).reverse().toString());
    }
}

// Run: java RulesDemo.java
// Output:
// Factorial of 10: 3628800
// Is 17 prime? true
// Is 18 prime? false
// Reversed: 11 avaJ
// Palindrome 'racecar': true
// Palindrome 'hello': false
// Primes > 10: [11, 13, 17, 19, 23, 29]

5.2 What Does NOT Work

## ERROR: Cannot reference classes in other files
## If Helper.java is a separate file, this will NOT work:
## java Main.java    (where Main.java imports from Helper.java)

## ERROR: Cannot add classpath dependencies
## java --classpath lib/gson.jar Script.java    -- NOT SUPPORTED

## ERROR: If first class has no main method
## The first class MUST contain main(String[] args)

## WORKS: Specifying source version
java --source 11 Script.java

## WORKS: Passing JVM options before the filename
java -Xmx512m -Denv=prod Script.java arg1 arg2

6. Before vs After Comparison

Here is a side-by-side comparison showing how single-file execution simplifies various workflows:

6.1 Running a Quick Program

Before (Java 10 and earlier) After (Java 11+)
1. Write HelloWorld.java 1. Write HelloWorld.java
2. javac HelloWorld.java 2. java HelloWorld.java
3. Verify HelloWorld.class was created Done.
4. java HelloWorld
5. Clean up .class files

6.2 Testing an Algorithm Idea

Before After
Open IDE Open any text editor
Create new project Write code in a single file
Configure build settings java Algorithm.java
Create package directory Done.
Write code
Build project
Run
Delete project when done

6.3 Feature Comparison

Feature Traditional (javac + java) Single-File (java only)
Commands needed 2 (compile + run) 1 (run)
Files created .class files on disk None (in-memory only)
Multiple source files Yes No (single file only)
External JARs Yes (–classpath) No
Startup speed Faster (pre-compiled) Slower (compiles each run)
Shebang support No Yes
Best for Production applications Scripts, prototypes, learning

7. Use Cases

Single-file execution is not meant to replace build tools for production applications. It fills a specific niche — situations where creating a full project is overkill. Here are the sweet spots:

7.1 Quick Scripting

Need to rename 500 files, parse a log, or generate test data? Write a Java script and run it directly:

// File: RenameFiles.java
// Quick script to rename files in a directory

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;

public class RenameFiles {
    public static void main(String[] args) throws IOException {
        if (args.length < 2) {
            System.out.println(
                "Usage: java RenameFiles.java  ");
            System.out.println(
                "Example: java RenameFiles.java ./photos vacation_");
            return;
        }

        Path dir = Paths.get(args[0]);
        String prefix = args[1];

        if (!Files.isDirectory(dir)) {
            System.out.println("Error: " + dir + " is not a directory");
            return;
        }

        int[] counter = {1};
        try (Stream files = Files.list(dir)) {
            files.filter(Files::isRegularFile)
                .sorted()
                .forEach(file -> {
                    String ext = getExtension(file.getFileName().toString());
                    String newName = String.format("%s%03d%s",
                        prefix, counter[0]++, ext);
                    Path target = file.resolveSibling(newName);
                    try {
                        Files.move(file, target);
                        System.out.println(
                            file.getFileName() + " -> " + newName);
                    } catch (IOException e) {
                        System.err.println("Failed to rename "
                            + file + ": " + e.getMessage());
                    }
                });
        }

        System.out.println("Renamed " + (counter[0] - 1) + " files.");
    }

    static String getExtension(String filename) {
        int dot = filename.lastIndexOf('.');
        return dot > 0 ? filename.substring(dot) : "";
    }
}

// Run: java RenameFiles.java ./photos vacation_
// Output:
// IMG_001.jpg -> vacation_001.jpg
// IMG_002.jpg -> vacation_002.jpg
// IMG_003.png -> vacation_003.png
// Renamed 3 files.

7.2 Prototyping and Learning

Want to test how a new Java feature works? Just write a quick file and run it. No project setup, no IDE required:

// File: TryNewFeatures.java
// Quick prototype to test Java features

import java.util.List;
import java.util.Map;
import java.util.Optional;

public class TryNewFeatures {
    public static void main(String[] args) {

        // Test List.of() (Java 9+)
        List fruits = List.of("Apple", "Banana", "Cherry");
        System.out.println("Immutable list: " + fruits);

        // Test Map.of() (Java 9+)
        Map scores = Map.of(
            "Alice", 95,
            "Bob", 87,
            "Charlie", 92
        );
        System.out.println("Scores: " + scores);

        // Test Optional
        Optional found = fruits.stream()
            .filter(f -> f.startsWith("B"))
            .findFirst();
        found.ifPresent(f -> System.out.println("Found: " + f));

        // Test String methods (Java 11)
        String text = "   Hello, Java 11!   ";
        System.out.println("strip(): '" + text.strip() + "'");
        System.out.println("isBlank: " + "   ".isBlank());
        System.out.println("lines: " + "a\nb\nc".lines().count());
        System.out.println("repeat: " + "ha".repeat(3));
    }
}

// Run: java TryNewFeatures.java
// Output:
// Immutable list: [Apple, Banana, Cherry]
// Scores: {Alice=95, Charlie=92, Bob=87}
// Found: Banana
// strip(): 'Hello, Java 11!'
// isBlank: true
// lines: 3
// repeat: hahaha

7.3 DevOps Utilities

System administrators and DevOps engineers who know Java can write utilities without switching to Bash or Python:

// File: HealthCheck.java
// Quick health check script for web services

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.time.Instant;
import java.util.List;

public class HealthCheck {
    public static void main(String[] args) {
        List endpoints = args.length > 0
            ? List.of(args)
            : List.of(
                "https://www.google.com",
                "https://api.github.com",
                "https://jsonplaceholder.typicode.com/posts/1"
            );

        HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(5))
            .build();

        System.out.printf("%-45s %-8s %-10s%n",
            "ENDPOINT", "STATUS", "TIME(ms)");
        System.out.println("-".repeat(65));

        for (String url : endpoints) {
            checkEndpoint(client, url);
        }
    }

    static void checkEndpoint(HttpClient client, String url) {
        try {
            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .timeout(Duration.ofSeconds(10))
                .build();

            Instant start = Instant.now();
            HttpResponse response = client.send(request,
                HttpResponse.BodyHandlers.discarding());
            long elapsed = Duration.between(start, Instant.now())
                .toMillis();

            String status = response.statusCode() < 400 ? "OK" : "FAIL";
            System.out.printf("%-45s %-8s %d ms%n",
                url, status + " (" + response.statusCode() + ")", elapsed);
        } catch (Exception e) {
            System.out.printf("%-45s %-8s %s%n",
                url, "ERROR", e.getClass().getSimpleName());
        }
    }
}

// Run: java HealthCheck.java
// Output:
// ENDPOINT                                      STATUS   TIME(ms)
// -----------------------------------------------------------------
// https://www.google.com                         OK (200) 142 ms
// https://api.github.com                         OK (200) 287 ms
// https://jsonplaceholder.typicode.com/posts/1   OK (200) 198 ms

8. Practical Examples

8.1 File Processor Script

A script that reads a text file and produces statistics -- word count, line count, character frequencies, and the longest line:

// File: FileStats.java
// Analyze a text file and print statistics

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import java.util.stream.Collectors;

public class FileStats {
    public static void main(String[] args) throws IOException {
        if (args.length == 0) {
            System.out.println("Usage: java FileStats.java ");
            return;
        }

        Path file = Path.of(args[0]);
        if (!Files.exists(file)) {
            System.out.println("Error: File not found: " + file);
            return;
        }

        String content = Files.readString(file);
        var lines = content.lines().collect(Collectors.toList());
        String[] words = content.split("\\s+");

        System.out.println("=== File Statistics: " + file.getFileName()
            + " ===");
        System.out.println("Lines:      " + lines.size());
        System.out.println("Words:      " + words.length);
        System.out.println("Characters: " + content.length());
        System.out.println("Bytes:      " + Files.size(file));

        // Average word length
        double avgWordLen = Arrays.stream(words)
            .mapToInt(String::length)
            .average()
            .orElse(0);
        System.out.printf("Avg word length: %.1f chars%n", avgWordLen);

        // Longest line
        String longestLine = lines.stream()
            .max(Comparator.comparingInt(String::length))
            .orElse("");
        System.out.println("Longest line: " + longestLine.length()
            + " chars");
        System.out.println("  > " + longestLine.substring(0,
            Math.min(80, longestLine.length()))
            + (longestLine.length() > 80 ? "..." : ""));

        // Top 5 most common words
        Map wordFreq = Arrays.stream(words)
            .map(w -> w.toLowerCase().replaceAll("[^a-z]", ""))
            .filter(w -> w.length() > 2)
            .collect(Collectors.groupingBy(w -> w,
                Collectors.counting()));

        System.out.println("\nTop 5 words:");
        wordFreq.entrySet().stream()
            .sorted(Map.Entry.comparingByValue()
                .reversed())
            .limit(5)
            .forEach(e -> System.out.printf(
                "  %-15s %d%n", e.getKey(), e.getValue()));
    }
}

// Run: java FileStats.java myfile.txt
// Output:
// === File Statistics: myfile.txt ===
// Lines:      42
// Words:      350
// Characters: 2150
// Bytes:      2150
// Avg word length: 5.1 chars
// Longest line: 78 chars
//   > This is the longest line in the file containing various words and information
//
// Top 5 words:
//   the             23
//   java            15
//   and             12
//   with            8
//   for             7

8.2 System Information Script

// File: SystemReport.java
// Generate a system information report

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.lang.management.RuntimeMXBean;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Properties;

public class SystemReport {
    public static void main(String[] args) {
        System.out.println("=" .repeat(50));
        System.out.println("     SYSTEM REPORT - " + LocalDateTime.now()
            .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        System.out.println("=".repeat(50));

        // Operating System
        OperatingSystemMXBean os = ManagementFactory
            .getOperatingSystemMXBean();
        System.out.println("\n--- Operating System ---");
        System.out.println("Name:         " + os.getName());
        System.out.println("Version:      " + os.getVersion());
        System.out.println("Architecture: " + os.getArch());
        System.out.println("Processors:   " + os.getAvailableProcessors());
        System.out.printf("Load Average: %.2f%n", os.getSystemLoadAverage());

        // JVM Info
        RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
        System.out.println("\n--- JVM ---");
        System.out.println("Name:    " + runtime.getVmName());
        System.out.println("Vendor:  " + runtime.getVmVendor());
        System.out.println("Version: " + runtime.getVmVersion());
        Duration uptime = Duration.ofMillis(runtime.getUptime());
        System.out.printf("Uptime:  %d min %d sec%n",
            uptime.toMinutes(), uptime.toSecondsPart());

        // Memory
        MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
        long heapUsed = memory.getHeapMemoryUsage().getUsed() / (1024 * 1024);
        long heapMax = memory.getHeapMemoryUsage().getMax() / (1024 * 1024);
        long nonHeapUsed = memory.getNonHeapMemoryUsage().getUsed()
            / (1024 * 1024);
        System.out.println("\n--- Memory ---");
        System.out.println("Heap Used:     " + heapUsed + " MB");
        System.out.println("Heap Max:      " + heapMax + " MB");
        System.out.println("Non-Heap Used: " + nonHeapUsed + " MB");

        // Environment Variables (selected)
        System.out.println("\n--- Environment ---");
        printEnv("JAVA_HOME");
        printEnv("PATH");
        printEnv("HOME");
        printEnv("USER");

        System.out.println("\n" + "=".repeat(50));
        System.out.println("Report complete.");
    }

    static void printEnv(String name) {
        String value = System.getenv(name);
        if (value != null) {
            // Truncate long values
            if (value.length() > 60) {
                value = value.substring(0, 57) + "...";
            }
            System.out.println(name + ": " + value);
        }
    }
}

// Run: java SystemReport.java
// Output:
// ==================================================
//      SYSTEM REPORT - 2026-02-28 15:42:00
// ==================================================
//
// --- Operating System ---
// Name:         Mac OS X
// Version:      13.4
// Architecture: aarch64
// Processors:   10
// Load Average: 2.45
//
// --- JVM ---
// Name:    OpenJDK 64-Bit Server VM
// Vendor:  Eclipse Adoptium
// Version: 11.0.2+9
// Uptime:  0 min 1 sec
//
// --- Memory ---
// Heap Used:     12 MB
// Heap Max:      4096 MB
// Non-Heap Used: 8 MB
//
// --- Environment ---
// JAVA_HOME: /Library/Java/JavaVirtualMachines/temurin-11.jdk/...
// PATH: /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library...
// HOME: /Users/developer
// USER: developer
//
// ==================================================
// Report complete.

8.3 CSV Parser Script

// File: CsvParser.java
// Parse a CSV file and display formatted results

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

public class CsvParser {
    public static void main(String[] args) throws IOException {
        if (args.length == 0) {
            // Create a sample CSV for demonstration
            String sampleCsv = "Name,Department,Salary,YearsExp\n"
                + "Alice,Engineering,95000,8\n"
                + "Bob,Marketing,72000,5\n"
                + "Charlie,Engineering,105000,12\n"
                + "Diana,HR,68000,3\n"
                + "Eve,Engineering,115000,15\n"
                + "Frank,Marketing,78000,7\n"
                + "Grace,HR,71000,4\n"
                + "Henry,Engineering,92000,6";

            Files.writeString(Path.of("sample.csv"), sampleCsv);
            System.out.println("Created sample.csv");
            System.out.println(
                "Run: java CsvParser.java sample.csv\n");
            args = new String[]{"sample.csv"};
        }

        Path csvFile = Path.of(args[0]);
        List lines = Files.readAllLines(csvFile);

        if (lines.isEmpty()) {
            System.out.println("Error: Empty CSV file");
            return;
        }

        // Parse header
        String[] headers = lines.get(0).split(",");

        // Parse rows
        List rows = new ArrayList<>();
        for (int i = 1; i < lines.size(); i++) {
            rows.add(lines.get(i).split(","));
        }

        // Print formatted table
        System.out.println("\n=== CSV Data (" + rows.size()
            + " rows) ===\n");
        System.out.printf("%-12s %-15s %-10s %-10s%n",
            (Object[]) headers);
        System.out.println("-".repeat(50));
        for (String[] row : rows) {
            System.out.printf("%-12s %-15s $%-9s %-10s%n",
                (Object[]) row);
        }

        // Statistics (assuming Salary is column 2)
        System.out.println("\n=== Statistics ===\n");
        DoubleSummaryStatistics salaryStats = rows.stream()
            .mapToDouble(row -> Double.parseDouble(row[2]))
            .summaryStatistics();

        System.out.printf("Total Records:  %d%n", salaryStats.getCount());
        System.out.printf("Average Salary: $%,.0f%n",
            salaryStats.getAverage());
        System.out.printf("Min Salary:     $%,.0f%n",
            salaryStats.getMin());
        System.out.printf("Max Salary:     $%,.0f%n",
            salaryStats.getMax());
        System.out.printf("Total Payroll:  $%,.0f%n",
            salaryStats.getSum());

        // Group by department
        System.out.println("\n=== By Department ===\n");
        rows.stream()
            .collect(Collectors.groupingBy(
                row -> row[1],
                Collectors.averagingDouble(row ->
                    Double.parseDouble(row[2]))))
            .forEach((dept, avg) ->
                System.out.printf("%-15s Avg Salary: $%,.0f%n",
                    dept, avg));
    }
}

// Run: java CsvParser.java sample.csv
// Output:
// === CSV Data (8 rows) ===
//
// Name         Department      Salary     YearsExp
// --------------------------------------------------
// Alice        Engineering     $95000     8
// Bob          Marketing       $72000     5
// Charlie      Engineering     $105000    12
// Diana        HR              $68000     3
// Eve          Engineering     $115000    15
// Frank        Marketing       $78000     7
// Grace        HR              $71000     4
// Henry        Engineering     $92000     6
//
// === Statistics ===
//
// Total Records:  8
// Average Salary: $87,000
// Min Salary:     $68,000
// Max Salary:     $115,000
// Total Payroll:  $696,000
//
// === By Department ===
//
// Engineering     Avg Salary: $101,750
// Marketing       Avg Salary: $75,000
// HR              Avg Salary: $69,500

9. Best Practices

Single-file execution is a tool, and like any tool, it works best when you use it for the right job:

Situation Use Single-File Use Full Project
Quick prototype / test an idea Yes
One-time script (rename files, parse data) Yes
Learning / teaching Java Yes
Code interview practice Yes
Need external libraries (Gson, JDBC driver) Yes
Multiple source files / packages Yes
Production application Yes
Needs unit tests Yes
Startup time matters (called frequently) Yes (pre-compiled)
Shared/reusable code Yes

Naming conventions:

  • For .java files: Use PascalCase matching the main class name (e.g., FileStats.java, HealthCheck.java)
  • For shebang scripts: Use lowercase with hyphens, no extension (e.g., health-check, file-stats, deploy)
  • Put utility scripts in a ~/scripts or ~/bin directory added to your PATH

Tips for writing good single-file programs:

  • Keep it focused -- one file, one purpose. If you need more than 200-300 lines, consider a proper project.
  • Handle errors -- a script that crashes with a stack trace is not useful. Print clear error messages for bad input.
  • Accept arguments -- use args[] for input rather than hardcoding values. Print usage instructions when no arguments are given.
  • Use Java standard library -- you have the entire JDK available. java.nio.file, java.net.http, java.time, and java.util.stream cover most scripting needs.
  • Add comments -- scripts are often revisited months later. A few lines at the top explaining what the script does saves future-you time.
  • Know when to graduate -- if your single file grows beyond 300 lines, needs external libraries, or will be maintained by others, create a proper Maven/Gradle project.



Subscribe To Our Newsletter
You will receive our latest post and tutorial.
Thank you for subscribing!

required
required


Leave a Reply

Your email address will not be published. Required fields are marked *