Working With Java Programs

The classic structure

public class Calculator {

    public static void main(String[] args) {
        System.out.println("start");
    }
}
  • public class Calculator — file must be Calculator.java
  • static — the JVM can call it without an object
  • String[] args — command line arguments

The compact form (Java 25) does the same thing:

void main() {
    IO.println("start");
}

Both may contain fields and methods:

final double VAT = 0.19;

double gross(double net) { return net * (1 + VAT); }

void main() { IO.println(gross(100)); }
Note

Compact for scripts and exercises, classic for real projects. The rest of the language is identical.

Compile and run

java Calculator.java          # run a single file directly
javac Calculator.java         # produce Calculator.class
java Calculator

javac -d out $(find src -name "*.java")
java -cp out com.example.Calculator
void main(String[] args) {
    if (args.length < 2) {
        IO.println("usage: java Calculator.java <a> <b>");
        return;
    }
    var a = Integer.parseInt(args[0]);
    var b = Integer.parseInt(args[1]);
    IO.println(a + b);
}

Reading errors

Compile time — the program never runs:

Calculator.java:5: error: incompatible types: String cannot be converted to int
    int x = "hello";
            ^

Runtime — read the stack trace bottom-up:

Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Calculator.divide(Calculator.java:12)
        at Calculator.main(Calculator.java:5)

Catching exceptions

try {
    var n = Integer.parseInt(input);
    IO.println(100 / n);
} catch (NumberFormatException | ArithmeticException e) {
    IO.println("bad input: " + e.getMessage());
} finally {
    IO.println("always runs");
}
Unchecked Checked
base class RuntimeException Exception
must be handled no yes — catch or throws
typical NullPointerException, IllegalArgumentException IOException, SQLException
String read(Path p) throws IOException {   // pass it up
    return Files.readString(p);
}

throw new IllegalArgumentException("age must not be negative: " + age);

Details in chapter 12.

Files

import java.nio.file.Files;
import java.nio.file.Path;

var path = Path.of("notes.txt");

Files.writeString(path, "line 1\nline 2\n");
Files.writeString(path, "line 3\n", StandardOpenOption.APPEND);

var content = Files.readString(path);
for (var line : Files.readAllLines(path)) IO.println(line);

Large files — stream them, and close the stream:

try (var lines = Files.lines(Path.of("big.log"))) {
    lines.filter(l -> l.contains("ERROR")).limit(10).forEach(IO::println);
}

try (...) closes everything automatically, even when an exception is thrown:

try (var writer = Files.newBufferedWriter(Path.of("out.txt"))) {
    writer.write("hello");
    writer.newLine();
}

Paths:

var p = Path.of("data", "2025", "report.csv");

Files.exists(p);  Files.isDirectory(p);  Files.size(p);
Files.createDirectories(p.getParent());
Files.deleteIfExists(p);
p.getFileName();  p.toAbsolutePath();

UTF-8 is the default since Java 18 — no charset arguments needed.

A complete program

import java.nio.file.*;

void main(String[] args) {
    if (args.length == 0) {
        IO.println("usage: java WordCount.java <file>");
        return;
    }
    try {
        var words = Files.readString(Path.of(args[0])).toLowerCase().split("\\W+");

        var counts = new java.util.HashMap<String, Integer>();
        for (var w : words) {
            if (!w.isBlank()) counts.merge(w, 1, Integer::sum);
        }

        counts.entrySet().stream()
            .sorted((a, b) -> b.getValue() - a.getValue())
            .limit(10)
            .forEach(e -> IO.println("%-15s %d".formatted(e.getKey(), e.getValue())));

    } catch (java.io.IOException e) {
        IO.println("cannot read file: " + e.getMessage());
    }
}

★ Exercises

  1. Run the word counter above on any text file.
  2. Add a second argument: how many words to print.
  3. Copy a file, adding line numbers.
  4. What happens on a missing file? Catch it and print something useful.
  5. Read a CSV of name;age;city into a list of records.
  6. Trigger a NullPointerException on purpose and read the stack trace.