在Java中,异常(Exception)是指程序在运行过程中发生的不正常情况 例如:
算数异常(ArithmeticException)
空指针异常(NullPointerException)
数组越界异常(ArrayIndexOutOfBoundsException) 
根据上述的异常信息可以看出:每个具体的异常都有一个类来进行描述

Throwable:是所有错误(Error)和异常(Exception)的父类。它有两个主要的子类:Error和Exception
Error:Error及其子类表示Java虚拟机(JVM)无法处理的严重问题。这些错误通常是不可恢复的,应用程序不应该尝试去捕捉这些错误
Exception:Exception及其子类表示应用程序可以捕获和处理的问题。Exception又可以分为两大类:
检查型异常(Checked Exception)非检查型异常(Unchecked Exception)下面是栈溢出错误代码示例:
public class Demo {
public void demo() {
demo();
}
public static void main(String[] args) {
Demo demo = new Demo();
demo.demo();
}
}运行结果:
Exception in thread "main" java.lang.StackOverflowError
在Java中,每次调用方法都会在虚拟机栈上为该方法开辟一个方法栈帧。上述代码中无限递归调用demo()方法就会无限地开辟方法栈帧。因为栈空间是有限的,所以就会抛出StackOverflowError错误。像这种错误一旦发生整个应用程序就会立刻崩溃,唯一的解决办法就是从根源上修改代码
检查型异常在编译阶段就会被检查,编译器强制要求程序员处理这些异常,比如:CloneNotSupportedException,IOException等。如果程序中抛出了这些异常,必须使用throws进行声明或者使用try-catch进行处理

非检查型异常在编译阶段不会被检查,是在运行时可能发生的异常,比如:ArithmeticException,NullPointerException,ArrayIndexOutOfBoundsException等。这些异常如果程序员不做处理,就会交给JVM进行处理

throw关键字用来显式抛出一个异常
public class Demo {
public static int function(int num){
if(num == 0){
throw new ArithmeticException();
}
return 10 / num;
}
public static void main(String[] args){
System.out.println(function(0));
}
}
throws关键字用于方法签名中,声明该方法可能抛出的异常。它主要用于处理检查型异常(Checked Exceptions),即那些在编译时需要被处理的异常。通过使用throws,方法可以声明它不处理某些异常,而是将异常的处理责任传递给调用该方法的代码

try-catch允许程序员捕捉并处理应用程序允许过程中可能出现的异常,从而防止程序因未处理的异常而中断
当程序中抛出非检查型异常时,如果程序员不介入解决,就会交由JVM来处理。当JVM处理异常时会中断当前应用程序
public class Demo {
public static void function(int num){
if(num == 0){
throw new ArithmeticException();
}
System.out.println("程序继续执行");
}
public static void main(String[] args){
function(0);
}
}运行结果:

使用try-catch处理该异常:
public class Demo {
public static void function(int num){
if(num == 0){
throw new ArithmeticException();
}
}
public static void main(String[] args){
try {
function(0);
}catch (ArithmeticException e){
System.out.println("成功捕捉到该异常并处理");
}
System.out.println("程序继续执行");
}
}运行结果:

注意:




finally是Java中异常处理机制的一部分,通常与try-catch块一起使用。无论try块中的代码是否抛出异常,finally块中的代码都会执行。在finally块中主要执行清理操作,如释放资源、关闭文件或数据库连接等

虽然Java中已经内置了非常多的异常类,但不一定完全符合用户的需求,所以用户也可以自定义自己期望的异常
如果希望自定义非检查型异常,可以继承自RuntimeException及其子类
public class PasswordErrorException extends RuntimeException {
public PasswordErrorException() {
super();
}
public PasswordErrorException(String message) {
super(message);
}
}如果希望自定义检查型异常,可以继承自IOException等检查型异常
public class PasswordErrorException extends IOException {
public PasswordErrorException() {
super();
}
public PasswordErrorException(String message) {
super(message);
}
}public class PasswordErrorException extends RuntimeException {
public PasswordErrorException() {
super();
}
public PasswordErrorException(String message) {
super(message);
}
}
public class UsernameErrorException extends RuntimeException{
public UsernameErrorException(String message){
super(message);
}
public UsernameErrorException(){
super();
}
}
public class Login {
public void login(String username, String password){
if(!"admin".equals(username) ){
throw new UsernameErrorException("用户名错误");
}
if(!"123456".equals(password)){
throw new PasswordErrorException("密码错误");
}
System.out.println("登录成功");
}
public static void main(String[] args) {
Login login = new Login();
try {
login.login("admin", "123456");
}catch (UsernameErrorException | PasswordErrorException e){
//printStackTrace()方法可以打印出抛异常的具体位置
e.printStackTrace();
}
System.out.println("程序继续执行");
}
}