Because you don't alawys simply want to communicate an error by simply spewing data to the console. That is usually the course of last resort.
typically, you want to develop a structured error handling system. One notable featured of a structured system like this is is the ability to communicate an error condition to the caller of a function or procedure. in this instance if the caller is aware that there may be esceptional circumstances and is prepared to deal with this error communication from the callee, it is done so.
howeer, exception have a special property , that they will continue to exist as long as they are uncaught, going further and further back up the chain of callers until the 'signal' , the error, they represent is handled.
many times, errors ( exceptions ) ARE caught and dealt with ( handled ) without sending anything to the console.
The up-chaining, propagating exception system provides a baked-in-the-compiler , syntactically clean way of providing structured error handling.
error codes or signals can also be used for this purpose, but are not quite as syntactically smooth, and leave a lot of traces in the coding, of there being a lot of error handling code. Exceptions try to hide error handling, except where it is absolutely necessary, by using the compiler and runtime to keep track of error code status automatially.