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:
- Reads the entire source file into memory
- Compiles it in memory using the Java compiler (no
.classfile is written to disk) - Loads the compiled bytecode into the JVM
- Finds the
mainmethod in the first class declared in the file - Executes the
mainmethod
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.javaThe .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 X3.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 <name> [<name>...]");
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.003.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<Boolean, List<Integer>> 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: 8Shebang 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
.javaextension — 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 11for portability (uses thejavafrom 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<Integer> 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 arg26. 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 <directory> <prefix>");
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<Path> 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<String> fruits = List.of("Apple", "Banana", "Cherry");
System.out.println("Immutable list: " + fruits);
// Test Map.of() (Java 9+)
Map<String, Integer> scores = Map.of(
"Alice", 95,
"Bob", 87,
"Charlie", 92
);
System.out.println("Scores: " + scores);
// Test Optional
Optional<String> 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: hahaha7.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<String> 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<Void> 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 ms8. 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 <file>");
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<String, Long> 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.<String, Long>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 78.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<String> 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<String[]> 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,5009. 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
.javafiles: 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
~/scriptsor~/bindirectory 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, andjava.util.streamcover 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.