Skip to content

Java异常处理与常用API完全指南 ​

目录 ​


一、异常处理体系 ​

1.1 异常概述 ​

异常:代码出现的不正常现象,在Java中以类和对象的形式存在。

异常继承体系:

Throwable
├── Error(错误)
│   └── 相当于绝症,需要大规模重构代码
└── Exception(异常)
    ├── 编译时期异常
    │   └── Exception及其子类(RuntimeException除外)
    └── 运行时期异常
        └── RuntimeException及其子类

1.2 编译时期异常 vs 运行时期异常 ​

特性编译时期异常运行时期异常
语法检查语法正确,但调用方法时爆红语法正确,编写时不报错
运行时机必须处理后才能编译通过编译通过,运行时报错
典型例子FileNotFoundException, IOExceptionNullPointerException, ArrayIndexOutOfBoundsException
处理方式必须处理(throws或try-catch)一般不处理,修改代码逻辑

判断方法:

  • 按住Ctrl点击异常类,查看继承体系
  • 如果继承体系中有RuntimeException → 运行时期异常
  • 如果继承体系中没有RuntimeException → 编译时期异常

1.3 异常处理方式 ​

方式一:throws抛出异常 ​

格式:

java
修饰符 返回值类型 方法名(参数列表) throws 异常类名 {
    // 方法体
}

特点:

  • 将异常向上抛出,由调用者处理
  • 可以抛出多个异常:throws 异常1, 异常2
  • 如果多个异常有继承关系,只需抛出父类异常

示例:

java
public static void insert(String s) throws FileNotFoundException {
    if (!s.endsWith(".txt")) {
        throw new FileNotFoundException("文件找不到");
    }
    System.out.println("文件处理成功");
}

弊端:如果一直往上抛,可能导致一个功能的异常影响其他功能执行。

方式二:try-catch捕获异常 ​

格式:

java
try {
    // 可能出现异常的代码
} catch (异常类型 变量名) {
    // 异常处理方案
    e.printStackTrace(); // 打印详细异常信息
}

特点:

  • 捕获并处理异常,不影响后续代码执行
  • 可以有多个catch块捕获不同异常
  • 如果catch的异常有继承关系,可以直接catch父类异常

示例:

java
public static void main(String[] args) {
    String s = "abc.txt1";
    try {
        insert(s);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    System.out.println("删除功能");
    System.out.println("修改功能");
    System.out.println("查询功能");
}

多个catch块 ​

java
try {
    // 可能出现多种异常的代码
} catch (IOException e) {
    e.printStackTrace();
} catch (NullPointerException e) {
    e.printStackTrace();
}

1.4 finally关键字 ​

作用:不管是否捕获到异常,finally块中的代码都会执行。

格式:

java
try {
    // 可能出现异常的代码
} catch (异常类型 变量名) {
    // 异常处理
} finally {
    // 一定会执行的代码
}

使用场景:

  • 释放资源(IO流、数据库连接、Socket等)
  • 清理工作

示例:

java
public static int method() {
    try {
        String s = null;
        System.out.println(s.length());
        return 2;
    } catch (Exception e) {
        return 1;
    } finally {
        System.out.println("我一定要执行");
    }
}

注意:即使try或catch中有return语句,finally也会在return之前执行。

1.5 异常处理注意事项 ​

子类重写方法时的异常抛出规则:

  • 父类方法抛异常 → 子类重写后可抛可不抛
  • 父类方法没抛异常 → 子类重写后不能抛异常

throws和try-catch的使用时机:

  • 如果处理异常后想让后续代码正常执行 → 使用try-catch
  • 如果方法之间是递进调用关系 → 可以先throws,最后统一try-catch处理

1.6 打印异常信息的三个方法 ​

Throwable类的方法:

方法说明示例输出
String toString()返回异常类型和异常信息java.io.FileNotFoundException: 文件找不到
String getMessage()获取异常信息文件找不到
void printStackTrace()获取最详细的异常信息(包括堆栈跟踪)完整的异常堆栈信息

推荐使用:printStackTrace() - 信息最详细,便于调试。


二、BigInteger大整数处理 ​

2.1 BigInteger概述 ​

作用:处理超出long类型范围的超大整数。

可表示范围:理论上无限大(受内存限制)。

2.2 BigInteger使用 ​

构造方法:

java
BigInteger(String val)

字符串内容必须是数字格式。

常用方法:

方法说明
BigInteger add(BigInteger val)加法
BigInteger subtract(BigInteger val)减法
BigInteger multiply(BigInteger val)乘法
BigInteger divide(BigInteger val)除法
int intValue()转换为int
long longValue()转换为long

示例:

java
BigInteger b1 = new BigInteger("12121212121212121212121212121212121");
BigInteger b2 = new BigInteger("12121212121212121212121212121212121");

BigInteger sum = b1.add(b2);
BigInteger diff = b1.subtract(b2);
BigInteger product = b1.multiply(b2);
BigInteger quotient = b1.divide(b2);

System.out.println("加法结果: " + sum);
System.out.println("减法结果: " + diff);
System.out.println("乘法结果: " + product);
System.out.println("除法结果: " + quotient);

三、BigDecimal精确计算 ​

3.1 BigDecimal概述 ​

作用:解决float和double类型直接参与运算时出现的精度损失问题。

问题示例:

java
float a = 3.55F;
float b = 2.12F;
float sum = a + b;
System.out.println(sum); // 输出: 5.6699998,而非预期的5.67

3.2 BigDecimal使用 ​

构造方法:

java
BigDecimal(String val)

推荐创建方式:

java
static BigDecimal valueOf(double val)

常用方法:

方法说明
BigDecimal add(BigDecimal val)加法
BigDecimal subtract(BigDecimal val)减法
BigDecimal multiply(BigDecimal val)乘法
BigDecimal divide(BigDecimal val)除法(除不尽会报错)
BigDecimal divide(BigDecimal divisor, int scale, RoundingMode mode)除法(指定精度和舍入方式)

RoundingMode舍入模式:

  • UP:向上加1
  • DOWN:直接舍去
  • HALF_UP:四舍五入

示例:

java
BigDecimal b1 = BigDecimal.valueOf(3.55);
BigDecimal b2 = BigDecimal.valueOf(2.12);

BigDecimal sum = b1.add(b2);
System.out.println("加法: " + sum); // 5.67

BigDecimal diff = b1.subtract(b2);
System.out.println("减法: " + diff); // 1.43

BigDecimal product = b1.multiply(b2);
System.out.println("乘法: " + product);

BigDecimal quotient = b1.divide(b2, 2, RoundingMode.HALF_UP);
System.out.println("除法(保留2位小数,四舍五入): " + quotient);

注意:除法如果除不尽且未指定精度和舍入模式,会抛出ArithmeticException。


四、Date日期类 ​

4.1 Date概述 ​

作用:表示特定的瞬间,精确到毫秒。

时间常识:

  • 1秒 = 1000毫秒
  • 北京时区:东八区(东经116.20,北纬39.56)
  • 时间原点:1970年1月1日 0时0分0秒(Unix纪元)

4.2 Date使用 ​

构造方法:

构造方法说明
Date()根据当前系统时间创建Date对象
Date(long time)根据指定毫秒值创建Date对象(从时间原点开始计算)

常用方法:

方法说明
void setTime(long time)设置时间(毫秒值)
long getTime()获取时间对应的毫秒值

示例:

java
Date date1 = new Date();
System.out.println("当前时间: " + date1);

Date date2 = new Date(1000L);
System.out.println("时间原点后1秒: " + date2);

date1.setTime(2000L);
System.out.println("设置后的时间: " + date1);

long millis = date2.getTime();
System.out.println("毫秒值: " + millis);

五、Calendar日历类 ​

5.1 Calendar概述 ​

特点:抽象类,用于操作日历字段。

获取对象:

java
static Calendar getInstance()

5.2 Calendar使用 ​

常用方法:

方法说明
int get(int field)返回给定日历字段的值
void set(int field, int value)将给定日历字段设置为指定值
void add(int field, int amount)为给定日历字段添加或减去指定时间量
Date getTime()将Calendar转换为Date对象
void set(int year, int month, int date)设置年月日

重要提示:Calendar中的月份从0开始计算(0=一月,1=二月,...,11=十二月)。

日历字段常量:

  • Calendar.YEAR - 年
  • Calendar.MONTH - 月
  • Calendar.DATE / Calendar.DAY_OF_MONTH - 日
  • Calendar.HOUR - 小时(12小时制)
  • Calendar.HOUR_OF_DAY - 小时(24小时制)
  • Calendar.MINUTE - 分钟
  • Calendar.SECOND - 秒

示例:

java
Calendar calendar = Calendar.getInstance();

int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // 注意:需要+1
int day = calendar.get(Calendar.DATE);

System.out.println("当前日期: " + year + "-" + month + "-" + day);

calendar.set(Calendar.YEAR, 2000);
System.out.println("设置年份后: " + calendar.get(Calendar.YEAR));

calendar.add(Calendar.YEAR, -1);
System.out.println("减1年后: " + calendar.get(Calendar.YEAR));

Date date = calendar.getTime();
System.out.println("转换为Date: " + date);

5.3 实用案例:计算某年2月有多少天 ​

java
public static int getDaysOfFebruary(int year) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, 2, 1); // 设置为3月1日(月份从0开始)
    calendar.add(Calendar.DATE, -1); // 减1天,得到2月最后一天
    return calendar.get(Calendar.DATE);
}

public static void main(String[] args) {
    System.out.println("2000年2月有" + getDaysOfFebruary(2000) + "天"); // 29天
    System.out.println("2001年2月有" + getDaysOfFebruary(2001) + "天"); // 28天
}

六、SimpleDateFormat日期格式化 ​

6.1 SimpleDateFormat概述 ​

作用:

  • 将Date对象按照指定格式格式化为字符串
  • 将符合格式的字符串解析为Date对象

构造方法:

java
SimpleDateFormat(String pattern)

6.2 格式化模式 ​

字母含义示例
y年yyyy → 2025
M月MM → 01-12
d日dd → 01-31
H时(24小时制)HH → 00-23
h时(12小时制)hh → 01-12
m分mm → 00-59
s秒ss → 00-59
E星期E → 星期五

常用模式:

  • yyyy-MM-dd → 2025-01-24
  • yyyy-MM-dd HH:mm:ss → 2025-01-24 15:30:45
  • yyyy年MM月dd日 E → 2025年01月24日 星期五

6.3 SimpleDateFormat使用 ​

常用方法:

方法说明
String format(Date date)将Date格式化为字符串
Date parse(String source)将字符串解析为Date

示例:

java
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

Date now = new Date();
String dateStr = sdf.format(now);
System.out.println("格式化后的日期: " + dateStr);

String str = "2025-01-24 15:30:00";
Date parsedDate = sdf.parse(str);
System.out.println("解析后的Date: " + parsedDate);

七、常见面试题 ​

⭐ 基础题 ​

1. 编译时期异常和运行时期异常的区别?

答案:

  • 编译时期异常:语法正确,但调用方法时编译器强制要求处理。必须使用throws或try-catch处理才能编译通过。例如:FileNotFoundException、IOException。
  • 运行时期异常:语法正确,编译时不报错,运行时才抛出。通常是代码逻辑错误导致,一般不需要显式处理,而是修改代码。例如:NullPointerException、ArrayIndexOutOfBoundsException。

2. throws和throw的区别?

答案:

  • throws:用在方法声明处,表示该方法可能抛出的异常,将异常抛给调用者处理。
  • throw:用在方法体内,用于手动创建并抛出一个异常对象。
java
public void method() throws IOException {
    throw new IOException("手动抛出异常");
}

3. finally块什么时候会执行?

答案: finally块无论是否捕获到异常都会执行。即使try或catch块中有return语句,finally也会在return之前执行。

特殊情况:如果在try或catch块中执行了System.exit(0),finally不会执行。


4. try-catch-finally的执行顺序?

答案:

  1. 执行try块
  2. 如果try块出现异常,执行对应的catch块
  3. 无论是否出现异常,都执行finally块
  4. 如果try或catch中有return,先执行finally,再执行return

⭐⭐ 进阶题 ​

5. 如何选择使用throws还是try-catch?

答案:

  • 使用try-catch:如果处理异常后,希望后续代码继续执行。
  • 使用throws:如果方法之间是递进调用关系,可以先throws,在最后统一用try-catch处理。
  • 实际开发:通常在业务逻辑层使用throws,在控制层或界面层使用try-catch统一处理。

6. 为什么float和double运算会丢失精度?如何解决?

答案: 原因:float和double采用IEEE 754浮点数标准,某些十进制小数无法精确表示为二进制浮点数,导致精度损失。

解决方案:使用BigDecimal类进行精确计算。

java
float a = 0.1f;
float b = 0.2f;
System.out.println(a + b); // 0.30000001

BigDecimal b1 = BigDecimal.valueOf(0.1);
BigDecimal b2 = BigDecimal.valueOf(0.2);
System.out.println(b1.add(b2)); // 0.3

7. Calendar类中月份为什么要+1?

答案: Calendar类中月份从0开始计算(0=一月,1=二月,...,11=十二月),这是设计上的历史原因。使用时需要:

  • 获取月份时:calendar.get(Calendar.MONTH) + 1
  • 设置月份时:calendar.set(Calendar.MONTH, 实际月份 - 1)

8. SimpleDateFormat是线程安全的吗?如何解决?

答案: SimpleDateFormat不是线程安全的,因为它在格式化过程中使用了实例变量来存储中间结果。

解决方案:

  1. 每次使用时创建新实例
  2. 使用ThreadLocal
  3. 使用JDK 8引入的DateTimeFormatter(线程安全)

⭐⭐⭐ 高级题 ​

9. 子类重写父类方法时,异常抛出有什么限制?

答案:

  • 父类方法抛出异常 → 子类重写方法可以抛出相同异常或其子类异常,也可以不抛出异常
  • 父类方法没有抛出异常 → 子类重写方法不能抛出编译时期异常(可以抛出运行时期异常)

原因:多态调用时,父类引用指向子类对象,编译器只看父类方法的异常声明。


10. 如何自定义异常?

答案:

  1. 继承Exception或RuntimeException
  2. 提供构造方法
java
public class MyException extends Exception {
    public MyException() {
        super();
    }
    
    public MyException(String message) {
        super(message);
    }
}

public class MyRuntimeException extends RuntimeException {
    public MyRuntimeException() {
        super();
    }
    
    public MyRuntimeException(String message) {
        super(message);
    }
}

使用场景:

  • 继承Exception → 编译时期异常,强制调用者处理
  • 继承RuntimeException → 运行时期异常,不强制处理

11. try-with-resources语法是什么?有什么优势?

答案: JDK 7引入的语法,用于自动关闭实现了AutoCloseable接口的资源。

java
try (FileInputStream fis = new FileInputStream("test.txt")) {
    // 使用资源
} catch (IOException e) {
    e.printStackTrace();
}
// 资源会自动关闭,无需finally

优势:

  • 代码简洁,无需手动关闭资源
  • 自动处理资源关闭时的异常
  • 确保资源一定会被关闭

12. 异常链(异常转译)是什么?如何实现?

答案: 异常链是指捕获一个异常后,抛出另一个异常,但保留原始异常信息。

java
try {
    // 可能抛出IOException
} catch (IOException e) {
    throw new MyException("业务处理失败", e); // 保留原始异常
}

使用场景:

  • 分层架构中,将底层异常转换为业务异常
  • 隐藏实现细节,提供更友好的异常信息

八、实用代码片段 ​

8.1 异常处理最佳实践 ​

java
public class ExceptionDemo {
    public void processFile(String filePath) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(filePath);
            // 处理文件
        } catch (FileNotFoundException e) {
            System.err.println("文件未找到: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public void processFileJava7(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath)) {
            // 处理文件
        } catch (IOException e) {
            System.err.println("IO异常: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

8.2 BigDecimal工具类 ​

java
public class BigDecimalUtil {
    private static final int DEF_DIV_SCALE = 10;
    
    public static double add(double v1, double v2) {
        BigDecimal b1 = BigDecimal.valueOf(v1);
        BigDecimal b2 = BigDecimal.valueOf(v2);
        return b1.add(b2).doubleValue();
    }
    
    public static double subtract(double v1, double v2) {
        BigDecimal b1 = BigDecimal.valueOf(v1);
        BigDecimal b2 = BigDecimal.valueOf(v2);
        return b1.subtract(b2).doubleValue();
    }
    
    public static double multiply(double v1, double v2) {
        BigDecimal b1 = BigDecimal.valueOf(v1);
        BigDecimal b2 = BigDecimal.valueOf(v2);
        return b1.multiply(b2).doubleValue();
    }
    
    public static double divide(double v1, double v2) {
        return divide(v1, v2, DEF_DIV_SCALE);
    }
    
    public static double divide(double v1, double v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("精度必须大于等于0");
        }
        BigDecimal b1 = BigDecimal.valueOf(v1);
        BigDecimal b2 = BigDecimal.valueOf(v2);
        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
    }
}

8.3 日期工具类 ​

java
public class DateUtil {
    private static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    
    public static String format(Date date) {
        return format(date, DEFAULT_PATTERN);
    }
    
    public static String format(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }
    
    public static Date parse(String dateStr) throws ParseException {
        return parse(dateStr, DEFAULT_PATTERN);
    }
    
    public static Date parse(String dateStr, String pattern) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.parse(dateStr);
    }
    
    public static int getDaysBetween(Date start, Date end) {
        long diff = end.getTime() - start.getTime();
        return (int) (diff / (1000 * 60 * 60 * 24));
    }
    
    public static Date addDays(Date date, int days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, days);
        return calendar.getTime();
    }
}

九、经典练习题 ​

基础题 ​

1. 异常捕获练习

编写一个程序,要求用户输入一个整数,如果输入的不是整数,捕获异常并提示重新输入。

java
public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    while (true) {
        try {
            System.out.print("请输入一个整数: ");
            int num = Integer.parseInt(scanner.nextLine());
            System.out.println("你输入的整数是: " + num);
            break;
        } catch (NumberFormatException e) {
            System.out.println("输入格式错误,请重新输入!");
        }
    }
    scanner.close();
}

2. BigDecimal计算练习

编写程序计算圆的面积,要求精确到小数点后2位。

java
public static void main(String[] args) {
    double radius = 5.5;
    double area = calculateCircleArea(radius);
    System.out.println("半径为" + radius + "的圆面积是: " + area);
}

public static double calculateCircleArea(double radius) {
    BigDecimal r = BigDecimal.valueOf(radius);
    BigDecimal pi = BigDecimal.valueOf(Math.PI);
    BigDecimal area = r.multiply(r).multiply(pi);
    return area.setScale(2, RoundingMode.HALF_UP).doubleValue();
}

3. Date和SimpleDateFormat练习

编写程序,将当前日期格式化为"2025年01月24日 星期五"的格式。

java
public static void main(String[] args) {
    Date now = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 E");
    String dateStr = sdf.format(now);
    System.out.println(dateStr);
}

进阶题 ​

4. 计算两个日期之间的天数

编写程序,输入两个日期字符串(格式:yyyy-MM-dd),计算它们之间相差多少天。

java
public static void main(String[] args) throws ParseException {
    String date1 = "2025-01-01";
    String date2 = "2025-01-24";
    
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date d1 = sdf.parse(date1);
    Date d2 = sdf.parse(date2);
    
    long diff = Math.abs(d2.getTime() - d1.getTime());
    int days = (int) (diff / (1000 * 60 * 60 * 24));
    
    System.out.println("相差" + days + "天");
}

5. 判断某年是否为闰年

使用Calendar类判断某年是否为闰年。

java
public static boolean isLeapYear(int year) {
    return getDaysOfFebruary(year) == 29;
}

public static int getDaysOfFebruary(int year) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, 2, 1);
    calendar.add(Calendar.DATE, -1);
    return calendar.get(Calendar.DATE);
}

public static void main(String[] args) {
    System.out.println("2000年是闰年吗? " + isLeapYear(2000));
    System.out.println("2001年是闰年吗? " + isLeapYear(2001));
    System.out.println("2024年是闰年吗? " + isLeapYear(2024));
}

6. 自定义异常练习

编写一个用户注册程序,要求:

  • 用户名长度3-10位
  • 密码长度6-15位
  • 年龄18-100岁 如果不满足条件,抛出自定义异常。
java
class RegisterException extends Exception {
    public RegisterException(String message) {
        super(message);
    }
}

public class RegisterDemo {
    public static void register(String username, String password, int age) 
            throws RegisterException {
        if (username.length() < 3 || username.length() > 10) {
            throw new RegisterException("用户名长度必须在3-10位之间");
        }
        if (password.length() < 6 || password.length() > 15) {
            throw new RegisterException("密码长度必须在6-15位之间");
        }
        if (age < 18 || age > 100) {
            throw new RegisterException("年龄必须在18-100岁之间");
        }
        System.out.println("注册成功!");
    }
    
    public static void main(String[] args) {
        try {
            register("张三", "123456", 25);
        } catch (RegisterException e) {
            System.out.println("注册失败: " + e.getMessage());
        }
    }
}

挑战题 ​

7. 实现一个简单的日志记录器

要求:

  • 记录时间戳、日志级别、日志内容
  • 日志级别:INFO、WARN、ERROR
  • 将日志写入文件
  • 使用异常处理确保资源正确关闭
java
enum LogLevel {
    INFO, WARN, ERROR
}

class Logger {
    private String logFile;
    
    public Logger(String logFile) {
        this.logFile = logFile;
    }
    
    public void log(LogLevel level, String message) {
        String timestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        String logLine = String.format("[%s] [%s] %s%n", timestamp, level, message);
        
        try (FileWriter fw = new FileWriter(logFile, true);
             BufferedWriter bw = new BufferedWriter(fw)) {
            bw.write(logLine);
        } catch (IOException e) {
            System.err.println("日志写入失败: " + e.getMessage());
        }
    }
}

public class LoggerDemo {
    public static void main(String[] args) {
        Logger logger = new Logger("app.log");
        logger.log(LogLevel.INFO, "应用程序启动");
        logger.log(LogLevel.WARN, "内存使用率较高");
        logger.log(LogLevel.ERROR, "数据库连接失败");
    }
}

8. 日期计算器

编写一个日期计算器,支持以下功能:

  • 计算两个日期之间的天数
  • 计算指定日期N天后的日期
  • 计算指定日期N天前的日期
  • 判断某天是星期几
java
public class DateCalculator {
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    
    public static int daysBetween(String date1, String date2) throws ParseException {
        Date d1 = sdf.parse(date1);
        Date d2 = sdf.parse(date2);
        long diff = Math.abs(d2.getTime() - d1.getTime());
        return (int) (diff / (1000 * 60 * 60 * 24));
    }
    
    public static String addDays(String date, int days) throws ParseException {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sdf.parse(date));
        calendar.add(Calendar.DATE, days);
        return sdf.format(calendar.getTime());
    }
    
    public static String getWeekDay(String date) throws ParseException {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(sdf.parse(date));
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        return weekDays[dayOfWeek];
    }
    
    public static void main(String[] args) throws ParseException {
        String date1 = "2025-01-01";
        String date2 = "2025-12-31";
        
        System.out.println("相差天数: " + daysBetween(date1, date2));
        System.out.println("100天后: " + addDays(date1, 100));
        System.out.println("100天前: " + addDays(date1, -100));
        System.out.println("星期: " + getWeekDay(date1));
    }
}

学习建议 ​

重点掌握 ​

  1. ⭐⭐⭐ 异常处理机制(try-catch-finally)
  2. ⭐⭐⭐ throws和throw的区别
  3. ⭐⭐⭐ BigDecimal解决精度问题
  4. ⭐⭐ SimpleDateFormat日期格式化
  5. ⭐⭐ Calendar日历操作

学习路径 ​

  1. 理解异常体系结构
  2. 掌握异常处理的两种方式
  3. 熟练使用BigDecimal进行精确计算
  4. 掌握Date、Calendar、SimpleDateFormat的使用
  5. 通过练习题巩固知识

常见误区 ​

  1. ❌ 混淆throws和throw的作用
  2. ❌ 忘记Calendar月份从0开始
  3. ❌ 使用double直接进行金额计算
  4. ❌ 忘记关闭IO资源
  5. ❌ SimpleDateFormat线程安全问题

实践建议 ​

  1. 多写异常处理的代码,理解执行流程
  2. 使用BigDecimal处理金额相关的计算
  3. 封装日期工具类,提高代码复用性
  4. 阅读JDK源码,理解异常体系设计
  5. 关注JDK 8新日期API(LocalDate、LocalDateTime)