为何月份异常消息与日、年异常消息输出不一致?
日期计算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
相关产品推荐
相关产品推荐

