包装类

包装类

包装类是一种将基本数据类型封装为对象的类。在Java中,每种基本数据类型都有对应的包装类,用于在需要对象的上下文中使用基本数据类型。

基本类型和对应包装类

  • byte 对应 Byte

  • short 对应 Short

  • int 对应 Integer

  • long 对应 Long

  • float 对应 Float

  • double 对应 Double

  • char 对应 Character

  • boolean 对应 Boolean

示例代码

// 使用包装类创建对象
Integer num1 = new Integer(10);
Double num2 = new Double(3.14);

// 自动装箱(Autoboxing)
Integer num3 = 20;
Double num4 = 6.28;

// 自动拆箱(Unboxing)
int value1 = num1.intValue();
double value2 = num2.doubleValue();

// 包装类与基本类型的比较
Integer num5 = 30;
int value3 = num5; // 自动拆箱
if (value3 == num5) {
    System.out.println("数值相等");
}

拆箱和装箱

拆箱(Unboxing)和装箱(Autoboxing)是Java中基本数据类型和对应包装类之间的自动转换过程。

装箱(Autoboxing)

装箱是将基本数据类型转换为对应的包装类对象的过程。在需要使用包装类对象的地方,可以直接将基本数据类型赋值给包装类对象,编译器会自动进行转换。

示例代码:

Integer num1 = 10; // 自动装箱
Double num2 = 3.14; // 自动装箱

拆箱(Unboxing)

拆箱是将包装类对象转换为对应的基本数据类型的过程。在需要使用基本数据类型的地方,可以直接将包装类对象赋值给基本数据类型变量,编译器会自动进行转换。

示例代码:

Integer num3 = new Integer(20);
int value1 = num3; // 自动拆箱

Double num4 = new Double(6.28);
double value2 = num4; // 自动拆箱

通过装箱和拆箱,可以方便地在基本数据类型和包装类对象之间进行转换,使代码更加简洁和易读。

异常

在Java中,异常是指程序在运行过程中发生的意外情况,例如除零、空指针引用等。异常处理是Java程序设计中的重要部分,可以保护程序免受错误的影响,并提供更好的用户体验。

异常类层次结构

Java中的异常是以类的形式存在的,它们都是Throwable类的子类。异常类主要分为两种:Error和Exception。

Exception的分类

Exception类是所有异常的父类,它又分为两种:受检异常(Checked Exception)和运行时异常(Runtime Exception)。

受检异常(Checked Exception)

受检异常是指在编译时必须进行处理的异常,即在代码中必须显式地进行捕获或声明抛出。受检异常通常是程序运行时可能出现的外部因素导致的异常,如文件不存在、网络连接中断等。

示例:IOException、SQLException等。

运行时异常(Runtime Exception)

运行时异常是指在运行时可能出现的异常,不需要在代码中显式地进行捕获或声明抛出。运行时异常通常是由程序逻辑错误导致的异常,如空指针引用、数组越界等。

示例:NullPointerException、ArrayIndexOutOfBoundsException等。

自定义异常

除了Java提供的异常类外,程序员还可以根据需要自定义异常类。自定义异常类通常继承自Exception或其子类,用于描述特定的异常情况,并可以根据业务需求添加额外的信息或处理逻辑。

通过对Exception类的分类,程序员可以更好地处理不同类型的异常情况,提高程序的健壮性和可靠性。

常见的异常类包括:

  • NullPointerException:空指针异常

  • ArithmeticException:算术异常,如除零

  • ArrayIndexOutOfBoundsException:数组下标越界异常

  • FileNotFoundException:文件未找到异常

  • IOException:输入输出异常

  • RuntimeException:运行时异常的基类

异常处理

在Java中,异常处理主要通过try-catch-finally语句块来实现。try块用于包含可能抛出异常的代码,catch块用于捕获并处理异常,finally块用于执行无论是否发生异常都需要执行的代码。

示例代码:

try {
    // 可能抛出异常的代码
    int result = 10 / 0; // 除零异常
} catch (ArithmeticException e) {
    // 捕获并处理异常
    System.out.println("除零异常:" + e.getMessage());
} finally {
    // 无论是否发生异常都会执行的代码
    System.out.println("异常处理结束");
}

抛出异常

除了捕获并处理异常,Java中还可以使用throw关键字手动抛出异常。通过throw关键字,可以在程序中根据特定条件主动抛出异常,以便在合适的地方进行处理。

示例代码:

public void checkAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("年龄不能为负数");
    }
    System.out.println("年龄为:" + age);
}

通过异常处理,可以使程序更加健壮,提高程序的可靠性和稳定性。

异常处理详解

在Java中,异常处理是通过一系列关键字和语句来实现的,包括trycatchfinallythrowsthrow。下面将详细解释这些关键字的用法,并给出示例代码。

try-catch-finally

  • trytry块用于包含可能抛出异常的代码块。在try块中的代码会被监视,一旦发生异常,程序会跳转到对应的catch块进行处理。

  • catchcatch块用于捕获并处理异常。在catch块中可以指定捕获的异常类型,并编写处理异常的代码逻辑。

  • finallyfinally块用于包含无论是否发生异常都需要执行的代码。通常用于释放资源或执行清理操作。即使遇到return 也会执行finally,除非虚拟机关闭。

示例代码:

try {
    int result = 10 / 0; // 除零异常
} catch (ArithmeticException e) {
    System.out.println("捕获到除零异常:" + e.getMessage());
} finally {
    System.out.println("无论是否发生异常,都会执行这里的代码");
}

throws

  • throwsthrows关键字用于在方法声明中指定可能抛出的异常类型。当方法中可能抛出异常时,可以使用throws关键字将异常抛给调用者处理。

示例代码:

public void readFile() throws IOException {
    // 读取文件的代码
}

throw

  • throwthrow关键字用于手动抛出异常。通过throw关键字,可以在程序中根据特定条件主动抛出异常,以便在合适的地方进行处理。

示例代码:

public void checkAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("年龄不能为负数");
    }
    System.out.println("年龄为:" + age);
}

通过try-catch-finallythrows关键字,可以处理和抛出异常;而通过throw关键字,可以手动抛出异常,从而更好地控制程序的异常处理流程。

在Java中,Exception类及其子类提供了多种方法来获取异常的详细信息。以下是一些常用的方法及其解释,配合代码示例:

1. getMessage()

  • 描述:返回一个描述异常的详细信息的字符串。

  • 示例代码

try {
    int result = 10 / 0; // 除零异常
} catch (ArithmeticException e) {
    System.out.println("异常信息: " + e.getMessage());
}

2. printStackTrace()

  • 描述:打印异常的详细堆栈跟踪信息,包括异常的类型、消息和发生异常的代码行。

  • 示例代码

try {
    String str = null;
    str.length(); // 空指针异常
} catch (NullPointerException e) {
    e.printStackTrace(); // 打印堆栈跟踪
}

3. toString()

  • 描述:返回异常的类名和详细信息的字符串,通常包含异常的类型和消息。

  • 示例代码

try {
    int[] arr = new int[2];
    int value = arr[5]; // 数组下标越界异常
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("异常描述: " + e.toString());
}

4. getCause()

  • 描述:返回导致当前异常的原因(即另一个异常),如果没有原因则返回null

  • 示例代码

try {
    throw new IllegalArgumentException("非法参数", new NullPointerException("参数为null"));
} catch (IllegalArgumentException e) {
    System.out.println("异常原因: " + e.getCause());
}

5. getStackTrace()

  • 描述:返回一个StackTraceElement数组,表示异常发生时的堆栈跟踪信息。

  • 示例代码

try {
    int result = 10 / 0; // 除零异常
} catch (ArithmeticException e) {
    StackTraceElement[] stackTrace = e.getStackTrace();
    for (StackTraceElement element : stackTrace) {
        System.out.println("类名: " + element.getClassName() + ", 方法名: " + element.getMethodName() + ", 行号: " + element.getLineNumber());
    }
}

6. fillInStackTrace()

  • 描述:用当前线程的堆栈跟踪信息填充异常的堆栈跟踪信息,通常用于在捕获异常后重新抛出异常。

  • 示例代码

try {
    throw new Exception("自定义异常");
} catch (Exception e) {
    e.fillInStackTrace(); // 填充堆栈跟踪
    throw e; // 重新抛出异常
}

多个 catch 块

在 Java 的异常处理中,一个 try 块可以包含多个 catch 块,用于捕获不同类型的异常并分别处理。当 try 块中的代码抛出异常时,程序会按照 catch 块的顺序逐个匹配异常类型,执行匹配到的第一个 catch 块,并且只会执行其中的代码块。

多个 catch 块的语法

try {
    // 可能抛出异常的代码
} catch (ExceptionType1 e1) {
    // 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2 类型的异常
} catch (Exception e) {
    // 处理其他类型的异常
} finally {
    // 无论是否发生异常都会执行的代码
}

多个 catch 块的执行流程

  1. 当 try 块中的代码抛出异常时,程序会按照 catch 块的顺序逐个匹配异常类型。

  2. 如果异常类型与某个 catch 块匹配,则执行该 catch 块中的代码,并结束异常处理流程。

  3. 如果异常类型与多个 catch 块匹配,则只会执行第一个匹配的 catch 块。

  4. 如果异常类型没有匹配任何 catch 块,则异常会被抛给上层调用者或者由 JVM 处理。

  5. 捕获先写范围小的,在写范围大的。

示例代码

try {
    int[] numbers = {1, 2, 3};
    System.out.println(numbers[3]); // 数组越界异常
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("捕获到数组越界异常:" + e.getMessage());
} catch (NullPointerException e) {
    System.out.println("捕获到空指针异常:" + e.getMessage());
} catch (Exception e) {
    System.out.println("捕获到其他异常:" + e.getMessage());
} finally {
    System.out.println("无论是否发生异常,都会执行这里的代码");
}

在上面的示例中,如果数组越界异常发生,则会匹配第一个 catch 块并执行相应的处理代码;如果是空指针异常,则会匹配第二个 catch 块;如果是其他类型的异常,则会匹配最后一个 catch 块。无论哪种异常发生,最终都会执行 finally 块中的代码。

通过多个 catch 块,可以根据不同类型的异常进行精细化的处理,提高程序的健壮性和可靠性。

自定义异常

在Java中,除了使用Java提供的异常类外,程序员还可以根据需要自定义异常类。自定义异常类通常继承自Exception或其子类,用于描述特定的异常情况,并可以根据业务需求添加额外的信息或处理逻辑。

自定义异常的步骤

  1. 创建一个继承自Exception或其子类以及超类throwable的自定义异常类。

  2. 在自定义异常类中添加构造方法,用于初始化异常信息。

  3. 可选:添加自定义方法或属性,以满足特定的异常处理需求。

示例代码

// 自定义异常类
class CustomException extends Exception {
    private int errorCode;

    // 构造方法,初始化异常信息
    public CustomException(String message, int errorCode) {
        super(message);
        this.errorCode = errorCode;
    }

    // 获取错误码的方法
    public int getErrorCode() {
        return errorCode;
    }
}

// 使用自定义异常
public class CustomExceptionExample {
    public static void main(String[] args) {
        try {
            validateAge(-1);
        } catch (CustomException e) {
            System.out.println("捕获到自定义异常:" + e.getMessage());
            System.out.println("错误码:" + e.getErrorCode());
        }
    }

    // 自定义方法,抛出自定义异常
    public static void validateAge(int age) throws CustomException {
        if (age < 0) {
            throw new CustomException("年龄不能为负数", 1001);
        }
        System.out.println("年龄为:" + age);
    }
}

在上面的示例中,我们定义了一个自定义异常类CustomException,它继承自Exception类,并添加了一个errorCode属性用于表示错误码。在CustomException类的构造方法中,我们初始化异常信息并设置错误码。然后在CustomExceptionExample类中,我们使用自定义异常类来处理年龄验证的逻辑。当年龄为负数时,会抛出自定义异常,并在捕获异常后输出异常信息和错误码。

通过自定义异常类,我们可以更好地描述和处理特定的异常情况,使程序的异常处理更加灵活和具有针对性。