Why is main() method allowed to declare exceptions?
Asked Answered
T

2

5

"Handle or declare. That's the law." - Head First

But, is it a good law? Let me give an example first:

public static void main(String[] args) throws Exception {
    m1();
}

static void m1() throws Exception{
    m2();
}

static void m2() throws Exception {
    throw new Exception();
}

m2() throws exception and m1() calls m2(), meaning it must either handle or declare it. Hmmm let's declare it. Then main() calls m1() and it has same poll: declare or handle. I again decided to declare it and code compiles just fine.

Okay, it works, but who handled this exception at all? Looks like no one did. I know I am a beginner, but I don't like the sound of that. Yes, some methods can decide whether to declare or handle exceptions, but why main()? Shouldn't main method be one that just handles? In that way, no exception could "slip".

Am I missing something to this? I was honestly surprised that it is okay for main method to just declare exception, knowing that it is the last place we could technically catch something.

Tanhya answered 19/10, 2020 at 18:14 Comment(8)
Exceptions are designed for unexpected situations where the state of the program is unknown. If you know about it, you can handle the exception. Otherwise it is better that the program crashes than that it goes ahead with bad data.Kielty
It goes to the default exception handler of the thread, which exists anyway because unchecked exceptions can also happen. It's considered best to handle exception in main itself, but you can just leave it to the default exception handler.Hallucination
@NomadMaker, I disagree that an exception means "the state of the program is unknown". An exception simply means "I was not able to do what was asked of me"... in general, take the name of the routine and add "I was not able to..." at the beginning of it... For example "ProcessFile" should throw an exception if it is unable to process the file. "ValidateLogin" should not throw an exception if the wrong password was provided... it was able to validate the user in that case, namely that the login failed. However, if the user database is unavailable, then it should throw an exception.Blackball
@Blackball If the exception is handled close to the source, you may be right. However, if an exception has been bucked all the way to main(), then there is an excellent chance that it would be impossible to reconstruct what happened. However, if a method could not do what was asked, then it should return an error value rather than throw an exception.Kielty
No one handles it -> program crashes. The faster you catch, the fewer code is stoppedNs
@NomadMaker, error codes lead to hard-to-read code in the best case, and forgotten checks in the worst case. That's why exceptions were introduced. The best use case for exceptions is not where they are handled "close to the code" nor are they "bucked up to main", but handled somewhere in the middle. For example, a method that processes multiple items can handle an exception thrown on one item (perhaps by logging it or creating a list of failed items) and continue to process the remaining items. "reconstructing exactly what happened" is not always a requirementBlackball
The simple answer: because the main method must comply with the Java specification. For handled exceptions, a method must contain a try/catch to handle exceptional cases OR it must declare that it can throw some Exception. The main method is not exempt from this rule. If this rule is violated, the code simply will not compile.Capsize
Yeah, it's back. That was weird.Kohima
K
6

who handled this exception at all?

The Java runtime did.

More specifically, the UncaughtExceptionHandler did, as specified in the Java Language Specification (JLS), section 11.3. Run-Time Handling of an Exception:

If no catch clause that can handle an exception can be found, then the current thread (the thread that encountered the exception) is terminated. Before termination, all finally clauses are executed and the uncaught exception is handled according to the following rules:

  • If the current thread has an uncaught exception handler set, then that handler is executed.

  • Otherwise, the method uncaughtException is invoked for the ThreadGroup that is the parent of the current thread. If the ThreadGroup and its parent ThreadGroups do not override uncaughtException, then the default handler's uncaughtException method is invoked.

So, by default, when main() throws an exception, unchecked or checked, the built-in default "uncaught exception handler" will simply print the stacktrace to System.err, as-if the following was executed right before main() was called:

Thread.setDefaultUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler());
class DefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        e.printStackTrace();
    }
}

After the "uncaught exception handler" has been invoked the thread is terminated, same as if you simply return from the main() method, and unless the code has started non-daemon threads that are still running, the program ends.

Kohima answered 19/10, 2020 at 18:51 Comment(2)
Technically the stack trace goes to System.err, not System.out.Mccollough
@Mccollough I was actually thinking that when I typed it, but my fingers still typed out. Dang muscle memory, or whatever it's called. Habit? <sigh>Kohima
T
0

Application may contain more than one class with main method. In that case application should declare a manifest to know which main is entrypoint (first called method). Main method can be called from another methods or another main method as a static method and can throw any exception. If you don't catch exception at least in entrypoint, then exception returned from your application to java virtual machine, then mashine deside what todo with exception. Usually jvm prints error message and return value other than 0 to operating system.

Telemeter answered 19/10, 2020 at 18:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.