Errors in Java

Here’s the Java translation of the Go code example for error handling, formatted in Markdown suitable for Hugo:

import java.util.Arrays;

public class ErrorHandling {

    // By convention, errors are represented by exceptions in Java.
    // We'll create a custom exception to represent our error.
    public static class CustomException extends Exception {
        public CustomException(String message) {
            super(message);
        }
    }

    // This method demonstrates returning a value or throwing an exception.
    public static int f(int arg) throws CustomException {
        if (arg == 42) {
            // Instead of returning an error, we throw an exception.
            throw new CustomException("can't work with 42");
        }
        // If no exception is thrown, we return the result.
        return arg + 3;
    }

    // Sentinel errors in Java are typically represented by constant Exception instances.
    public static final CustomException ERR_OUT_OF_TEA = new CustomException("no more tea available");
    public static final CustomException ERR_POWER = new CustomException("can't boil water");

    public static void makeTea(int arg) throws CustomException {
        if (arg == 2) {
            throw ERR_OUT_OF_TEA;
        } else if (arg == 4) {
            // In Java, we can't directly wrap exceptions like in Go.
            // Instead, we can use exception chaining.
            throw new CustomException("making tea: " + ERR_POWER.getMessage());
        }
        // No exception means success.
    }

    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 == ERR_OUT_OF_TEA) {
                    System.out.println("We should buy new tea!");
                } else if (e.getMessage().contains(ERR_POWER.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 rather than return values. Here’s an explanation of the key differences and concepts:

  1. Instead of returning error values, Java methods throw exceptions when an error occurs.

  2. The CustomException class is created to represent our custom errors. It extends the built-in Exception class.

  3. The f method now throws a CustomException instead of returning an error value.

  4. Sentinel errors are represented as constant Exception instances (ERR_OUT_OF_TEA and ERR_POWER).

  5. The makeTea method throws exceptions instead of returning error values.

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

  7. Instead of errors.Is, we use == to check for specific sentinel errors, and getMessage().contains() to check for wrapped errors. Java doesn’t have a direct equivalent to Go’s error wrapping, but we can achieve similar functionality by including the underlying error’s message in the new exception.

  8. The instanceof operator can be used to check the type of an exception, similar to type assertions in Go.

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 Go version, demonstrating various error handling scenarios in Java.