Errors in Squirrel

import java.util.Arrays;

public class ErrorHandling {

    // In Java, we use exceptions for error handling instead of
    // separate return values. We'll define a custom exception.
    public static class CustomException extends Exception {
        public CustomException(String message) {
            super(message);
        }
    }

    // This method throws an exception instead of returning an error
    public static int f(int arg) throws CustomException {
        if (arg == 42) {
            // In Java, we throw exceptions instead of returning them
            throw new CustomException("can't work with 42");
        }
        // If no exception is thrown, the method completes successfully
        return arg + 3;
    }

    // Sentinel errors in Java are typically implemented as static final
    // instances of custom exception classes
    public static final CustomException OUT_OF_TEA = new CustomException("no more tea available");
    public static final CustomException POWER_ERROR = new CustomException("can't boil water");

    public static void makeTea(int arg) throws CustomException {
        if (arg == 2) {
            throw OUT_OF_TEA;
        } else if (arg == 4) {
            // In Java, we can't wrap exceptions like in Go, but we can
            // create a new exception with the cause
            throw new CustomException("making tea: " + POWER_ERROR.getMessage());
        }
        // If no exception is thrown, the method completes successfully
    }

    public static void main(String[] args) {
        for (int i : Arrays.asList(7, 42)) {
            try {
                int r = f(i);
                System.out.println("f worked: " + r);
            } catch (CustomException 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 (CustomException e) {
                // In Java, we use instanceof to check the exception type
                if (e == OUT_OF_TEA) {
                    System.out.println("We should buy new tea!");
                } else if (e.getMessage().contains(POWER_ERROR.getMessage())) {
                    System.out.println("Now it is dark.");
                } else {
                    System.out.println("unknown error: " + e.getMessage());
                }
            }
        }
    }
}

In Java, error handling is typically done using exceptions. This contrasts with the explicit error return values used in some other languages. Java’s approach uses try-catch blocks to handle exceptions, making it easy to separate normal code flow from error handling.

Key points in this Java implementation:

  1. We define a custom exception CustomException to represent our errors.

  2. Methods that can fail throw exceptions instead of returning error values.

  3. Sentinel errors are implemented as static final instances of our custom exception.

  4. We use try-catch blocks to handle exceptions, which is analogous to checking returned errors in other languages.

  5. Java doesn’t have built-in error wrapping like some other languages, but we can achieve similar functionality by creating new exceptions with the cause or including the cause’s message.

  6. Instead of using errors.Is(), we use == for comparing exception instances and instanceof or message comparison for checking exception types.

To run this program, save it as ErrorHandling.java, compile it with javac ErrorHandling.java, and then run it with java ErrorHandling. The output will be similar to the original example, demonstrating how Java handles errors in a way that’s analogous to the original code.