University hammered into me the fact that goto statements are almost universally bad and should be avoided. I went to university in 2009 which is quite a while after the world figured that out (the wikipedia page for goto states that the structured programming movement of the 60s and 70s caused its decline, a good couple decades before I was even born), but it still gets bandied around even by those who were never traumatised by it.
It’s easy to be a little disconnected from why it was bad if you never experienced it. Really convoluted and difficult to read program flow - not always easy to tell where you’re coming from or going to. We killed it off largely with conditionals, loops and function calls, all serving the same purpose but with more limited semantics that help you understand the more controlled ways it works.
There’s still a very popular goto statement hiding in plain sight in your language today - throw (or raise, or panic or similar). Exception control flow is sadly a pattern still widely used by developers and even adopted intentionally in frameworks (exceptions being caught by HTTP middleware and transformed into status code returns, for example).
People don’t tend to think of it as a goto likely because more and more developers have never used that statement but effectively it is a jump instruction without a pre-determined destination. The destination is resolved through the try/catch convention or through a top level Uncaught Exception handler/process, usually just crashing the application. This can easily be harder to comprehend if you use catch blocks to filter exceptions (i.e. catch and suppress certain ones, let others bubble up) or as some kind of middleware (do something with the exception such as logging, then rethrow it).
I think exceptions are good, being able to destructively and forcibly stop an execution is a powerful tool - in a framework or ecosystem with a strong “let it fail” philosophy (think AWS Lambda & SQS error handling, or Erlang’s supervision trees) it can be much cleaner to work with than building your own inner fault tolerance. What’s not good is casually using exceptions as meaningful in-app control flow - I strongly dislike web applications that make use of exceptions to return status codes (the example I quoted above), as that’s heavily disconnecting the failure from the result and technically bleeding dressed up HTTP concerns into raw domain code.
Don’t use them as a goto though, please.