Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

When reading Java code you only need to pay attention to whether any resource that is acquired is also safely released - i.e. that no resources are acquired without using `using` or `try/finally`. This is the same as Go with `defer`.

Beyond that, you don't need to care if the function will terminate early because of an exception - as long as all necessary cleanup is handled regardless of exit reason, you don't care that the function will finish early if an HTTP request fails before using the value of the request.

And usually you only want to catch and re-throw exceptions around module (in the broad sense) boundaries. If you catch and re-throw exceptions in every function, you're either losing lower-level context completely OR you're leaking implementation details anyway if you're chaining up the old error.

In Go, the error needs to be manually propagated through every function, with enough context to understand what's going on. In Java, the error needs to be manually handled at every module boundary; function-level context is given automatically by the call-stack.



Java doesn't require you to handle exceptions. This is not the criteria you should use to determine if you need handle the exception.

The fact is that even code that does no resource acquiring could throw an exception. It might not even be a documented exception. And when it throws that exception that you may or may not have been expecting some code somewhere is going to have to figure out what to do. In java the only real way to communicate an error is to throw an exception. For some reason culturally Java has decided that it's too much work to distinguish between errors that should crash the app and errors that should be handled by the caller in some way. As a result when an exception outside of your code happens in production and you read the exception in your logs it will:

1. Not have a significant part of the information you need to debug the problem.

2. Be in code you may not have easy access to go read.

3. You will probably have no idea why it's happening.

Eventually for a long enough lived codebase you will have encountered and documented all of these in a runbook somewhere or you won't and everyone will have to have learned them over and over again.

If you are on an exceptional team you'll have caught and then wrapped or handled these exceptions to make operating the software in production less painful. But all of it could have been avoided if java had chosen a better path.

Make it impossible trap runtime exceptions. They just crash the program. Make trappable exceptions checked exceptions. The code would get more verbose. But the operational pain would have been vastly reduced.

Errors are a part of your API. Unchecked Runtime exceptions pretend like 50% of your API surface doesn't exist.


Normally, all server-style apps have some top-level error handlers that log the error and abandon or perhaps restart some piece of work (such as an HTTP request).

If these errors are things that the system administrator can handle, they will find them in the logs, the cause of the error will hopefully be clear enough if enough effort was spent on making it that way, and the sysadmin will fix the cause. If the error is something that the programmers never anticipated, nothing more can be done and a bug needs to be open with the developer. In some cases, even though the problem was with the environment, error reporting may have been fudged and the sysadmin may not be able to understand what they are suppose to fix - bad error reporting.

I fail to see how exceptions hurt with any of these cases. I have no more or less information about error cases seeing `func foo() error` or `void foo() throws Exception`, so neither helps me know what errors I should handle. It's no harder in Java to add context to errors when you really want/can - in fact, it's easier:

  try{ 
    stuff1(); 
    stuff2(); 
  } catch (Exception e) { 
    throw SpecificError("I was doing this when something else happened", e);
  }
vs

  err = stuff1(); 
  if err != nil { 
    return fmt.Errorf("I was doing this with stuff1 when something else happened: %w", err)
  } 
  err = stuff2(); 
  if err != nil {
    return fmt.Errorf("I was doing this with stuff2 when something else happened: %w", err)
    //note: different error message, since we're missing call stacks to know where this actually failed
  }
Errors are part of your API - agreed. In C# or Java without checked exceptions, you have to assume that any function can throw any exception. In Go, you get exactly 1 more bit of information: a function tells you IF it returns an error or not - same as modern C++ with `noexcept`. But if you actually want to know what errors are returned, you're SOL in most languages (Java with checked exceptions helps, but causes other problems). And none of these languages helps you with adding context to errors, except the so so context of stack traces in C# and Java.


We are so close to being in violent agreement.

I find that extra bit of information to be crucial you do not. I think you are perhaps discounting the value that Go allows you to add in your apis by making the error type explicit which then does tell you what error you might be getting. Go forces the programmer to make the fact that there is an error explicit which is good. If it also forced the developer to be explicit in which type of error it can return that would also be good since it would enforce API boundaries for errors. But I think Go is still ahead of the game compared to Java on this one.


Yes, I can see how valuing the error/no error distinction differently can significantly color the whole discussion. So, cheers for finding the point where we actually differ!




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: