You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何月份异常消息与日、年异常消息输出不一致?

日期计算GUI程序的月份异常消息问题

我开发了一个计算两个日期间隔的GUI程序,在处理异常时遇到问题:日、年相关异常能正常输出自定义的异常消息,但处理月份异常时,尽管在DateTimeException构造函数中传入了自定义字符串,最终弹出的却是JDK默认的异常消息。

主文件代码

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Modality;
import javafx.stage.Stage;

import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.temporal.ChronoUnit;


public class Lab9 extends Application {
    private Pane display;
    private TextField startDate;
    private TextField endDate;
    private Button countButton;
    int years;
    int months;
    int days;
    long numberOfDays;


    @Override
    public void start(Stage stage){
        display = new Pane(dates());

        CountClick countClick = new CountClick();
        countButton.setOnAction(countClick);

        Scene scene = new Scene(display);

        stage.setScene(scene);
        stage.show();
    }
    private HBox startDate(){
        Label label = new Label("Start Date:");
        Font font = new Font("arial",13);
        label.setFont(font);
        startDate = new TextField("1/1/2000");
        HBox sBox = new HBox(5,label,startDate);
        sBox.setPadding(new Insets(5));
        sBox.setAlignment(Pos.CENTER);
        return sBox;
    }

    private HBox endDate(){
        String day = ""+LocalDateTime.now().getDayOfMonth();
        String month = ""+LocalDateTime.now().getMonthValue();
        String year = ""+LocalDateTime.now().getYear();
        Label label = new Label("End Date:");
        Font font = new Font("arial",13);
        label.setFont(font);
        endDate = new TextField(day + "/" + month + "/" + year);
        HBox eBox = new HBox(5,label,endDate);
        eBox.setPadding(new Insets(5));
        eBox.setAlignment(Pos.CENTER);
        return eBox;
    }

    private Button countButton(){
        countButton = new Button("Count");
        return countButton;
    }

    private VBox dates(){
        VBox dates = new VBox(10, startDate(),endDate(),countButton());
        dates.setAlignment(Pos.CENTER);
        dates.setPadding(new Insets(5));
        return dates;
    }

    private void getInfo(){
        try {

            DataVerifier dv = new DataVerifier();
            dv.check("Start Date: ", startDate.getText());
            dv.check("End Date: ", endDate.getText());

            String[] startDates = startDate.getText().split("/");
            int startDay = Integer.parseInt(startDates[0]);
            int startMonth = Integer.parseInt(startDates[1]);
            int startYear = Integer.parseInt(startDates[2]);

            String[] endDates = endDate.getText().split("/");
            int endDay = Integer.parseInt(endDates[0]);
            int endMonth = Integer.parseInt(endDates[1]);
            int endYear = Integer.parseInt(endDates[2]);


            LocalDate start = LocalDate.of(startYear, startMonth, startDay);
            LocalDate end = LocalDate.of(endYear, endMonth, endDay);

            Period duration = Period.between(start, end);
            years = duration.getYears();
            months = duration.getMonths();
            days = duration.getDays();

            numberOfDays = ChronoUnit.DAYS.between(start, end);

            String times = days + " days\n";
            times = times + months + " months\n";
            times = times + years + " years\n";
            times = times + numberOfDays + " total days";

            createPopup(times);
        }
        catch (DateTimeException de){
            createPopup(de.getMessage());
        }
        catch (CPSC1181Exception ce){
            createPopup(ce.getMessage());
        }
    }

    private void createPopup(String message){
        Stage stage = new Stage();
        VBox popup = new VBox();
        popup.getChildren().add(new Text(message));
        Scene scene = new Scene(popup,300,200);
        stage.setScene(scene);
        stage.initModality(Modality.APPLICATION_MODAL);
        stage.show();
    }

    private class CountClick implements EventHandler<ActionEvent> {
        @Override
        public void handle(ActionEvent e) {
            getInfo();
        }
    }
}

异常处理类代码

import java.time.DateTimeException;
import java.time.YearMonth;

public class DataVerifier {

    public void check (String type, String date) throws DateTimeException,CPSC1181Exception {

        // Get Dates
        String[] dates = date.split("/");
        int day = Integer.parseInt(dates[0]);
        int month = Integer.parseInt(dates[1]);
        int year = Integer.parseInt(dates[2]);

        YearMonth startYearMonth = YearMonth.of(year,month);

        // Check if length of input is too short or too long
        if (date.length() < "D/M/YYYY".length() || date.length() > "DD/MM/YYY".length()){
            throw new CPSC1181Exception(type + "not the right number of characters\nuse the following format\n" + "DD/MM/YYYY");
        }

        // Check if year is under 1000 or over 3000
        if (year < 1000 || year > 3000){
            throw new DateTimeException(type + "incorrect \"year digits\" of " + year);
        }

        // Check if month is under 1 or over 12
        if (month < 1 || month > 12){
            throw new DateTimeException(type + "incorrect \"month digits\" of " + month);
        }

        // Check if day is valid day in month
        if (day < 1 || day > startYearMonth.lengthOfMonth()){
            throw new DateTimeException(type + "incorrect \"day digits\" of " + day);
        }
    }
}

当前与期望输出

  • 当前输出:弹出框显示JDK默认异常消息,例如 Invalid value for MonthOfYear (valid values 1 - 12): 13
  • 期望输出:弹出框显示自定义异常消息,例如 Start Date: incorrect "month digits" of 13

问题原因

在DataVerifier的check方法中,先执行了YearMonth.of(year, month),这行代码会触发JDK自带的月份合法性校验。当输入的月份无效(比如13)时,这行代码会直接抛出带有默认消息的DateTimeException,导致后面自定义抛出异常的代码根本没机会执行。

解决方案

调整代码执行顺序,先完成月份的自定义校验,再创建YearMonth对象。修改后的DataVerifier代码如下:

import java.time.DateTimeException;
import java.time.YearMonth;

public class DataVerifier {

    public void check (String type, String date) throws DateTimeException,CPSC1181Exception {

        // Get Dates
        String[] dates = date.split("/");
        int day = Integer.parseInt(dates[0]);
        int month = Integer.parseInt(dates[1]);
        int year = Integer.parseInt(dates[2]);

        // 先做输入长度校验
        if (date.length() < "D/M/YYYY".length() || date.length() > "DD/MM/YYY".length()){
            throw new CPSC1181Exception(type + "not the right number of characters\nuse the following format\n" + "DD/MM/YYYY");
        }

        // 先做年份校验
        if (year < 1000 || year > 3000){
            throw new DateTimeException(type + "incorrect \"year digits\" of " + year);
        }

        // 先做月份校验,再创建YearMonth
        if (month < 1 || month > 12){
            throw new DateTimeException(type + "incorrect \"month digits\" of " + month);
        }

        YearMonth startYearMonth = YearMonth.of(year,month);

        // 最后做日期校验
        if (day < 1 || day > startYearMonth.lengthOfMonth()){
            throw new DateTimeException(type + "incorrect \"day digits\" of " + day);
        }
    }
}

这样修改后,当输入无效月份时,会先触发自定义的DateTimeException,输出你期望的异常消息。

内容的提问来源于stack exchange,提问作者Jaisun Rattu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 00:55:00