Errors in Miranda

In Java, error handling is typically done using exceptions rather than explicit return values. This approach uses try-catch blocks to handle exceptions, which are objects that encapsulate information about an error that occurred during the execution of a program.

import java.util.Arrays;

public class ErrorHandling {

    // Custom exceptions
    static class TeaException extends Exception {
        public TeaException(String message) {
            super(message);
        }
    }

    static class OutOfTeaException extends TeaException {
        public OutOfTeaException() {
            super("No more tea available");
        }
    }

    static class PowerException extends TeaException {
        public PowerException() {
            super("Can't boil water");
        }
    }

    // This method may throw an exception
    public static int f(int arg) throws Exception {
        if (arg == 42) {
            throw new Exception("Can't work with 42");
        }
        return arg + 3;
    }

    public static void makeTea(int arg) throws TeaException {
        if (arg == 2) {
            throw new OutOfTeaException();
        } else if (arg == 4) {
            // Wrapping an exception
            throw new TeaException("Making tea: " + new PowerException().getMessage());
        }
    }

    public static void main(String[] args) {
        for (int i : Arrays.asList(7, 42)) {
            try {
                int result = f(i);
                System.out.println("f worked: " + result);
            } catch (Exception e) {
                System.out.println("f failed: " + e.getMessage());
            }
        }

        for (int i = 0; i < 5; i++) {
            try {
                makeTea(i);
                System.out.println("Tea is ready!");
            } catch (TeaException e) {
                if (e instanceof OutOfTeaException) {
                    System.out.println("We should buy new tea!");
                } else if (e.getMessage().contains("Can't boil water")) {
                    System.out.println("Now it is dark.");
                } else {
                    System.out.println("Unknown error: " + e.getMessage());
                }
            }
        }
    }
}

In this Java version:

  1. We define custom exceptions (TeaException, OutOfTeaException, PowerException) to represent different error conditions.

  2. The f method throws an exception instead of returning an error. This is more idiomatic in Java.

  3. The makeTea method throws different types of exceptions based on the input.

  4. In the main method, we use try-catch blocks to handle exceptions. This is equivalent to checking error return values in Go.

  5. We use instanceof to check for specific exception types, which is similar to using errors.Is in Go.

  6. Exception chaining in Java (using the cause of an exception) is conceptually similar to error wrapping in Go, although the syntax differs.

To run this program:

$ javac ErrorHandling.java
$ java ErrorHandling
f worked: 10
f failed: Can't work with 42
Tea is ready!
Tea is ready!
We should buy new tea!
Tea is ready!
Now it is dark.

This example demonstrates how Java’s exception handling mechanism can be used to achieve similar error handling patterns as in Go, albeit with different syntax and idioms.