Java实训:掌握利用API编程的方法,尽量使用类库&利用类库编写程序,可以输出当月的日历(包括周) 超高完成度!!!

实训目的

掌握利用API编程的方法,尽量使用类库。

实训要求

利用类库编写程序,可以输出当月的日历(包括周)

一、 思路梳理

看到实验要求后,很快有了思路:

使用Date类(java.util.Date而非java.sql.Date;)的无参构造方法获取当前日期,然后使用SimpleDateFormat类自定义日期格式,即可格式化输出当前日期。

使用Calendar对象,通过Calendar.getInstance(),获取当前日期和时间。
然后,设置日期设置为当月的第一天,获取这一天是星期几以及当月的总天数
仿照常见日历,输出日历的表头。根据第一天是星期几,预处理出合适的空格数
最后循环输出每一天的日期,注意在适当的时候回车。

二、 简简单单写个小程序

1. 思路理顺后,很简单就写出来了下面这段代码

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class version0 {

    public static void main(String[] args) {
        // 获取当前日期
        Date date = new Date();
        
        // 设置日期格式
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        
        //输出当前日期
        System.out.println("当前日期:" +  dateFormat.format(date));

        // 使用Calendar类获取当前月份
        Calendar calendar = Calendar.getInstance();
        
        // 设置Calendar对象的日期为当月的第一天
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        // 获取当月第一天是星期几
        int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);

        // 获取当月的天数
        int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

        // 输出日历表头
        System.out.println("日\t一\t二\t三\t四\t五\t六");

        // 输出日历内容
        for (int i = 1; i < firstDayOfWeek; i++) {
            System.out.print("\t");
        }

        for (int day = 1; day <= daysInMonth; day++) {
            System.out.print(day + "\t");

            if ((firstDayOfWeek + day - 1) % 7 == 0) {
                System.out.println(); // 换行
            }
        }
    }
}

2. 运行结果

当前日期:2023-11-18
日      一      二      三      四      五      六
                        1       2       3       4
5       6       7       8       9       10      11
12      13      14      15      16      17      18
19      20      21      22      23      24      25
26      27      28      29      30

3. 反思与总结

上述代码实现的功能:

  • 输出当前日期
  • 输出当前月的日历

待优化之处:

  • 缺少异常处理
  • 缺少用户交互
  • 没有模块化编程:

三、 尝试进行优化

1. 增加用户交互

为了允许用户输入,首先导入Scanner
import java.util.Scanner;

接下来实现用户交互即可

// 获取用户输入的年份和月份
Scanner scanner = new Scanner(System.in);
System.out.print("请输入年份:");
int year = scanner.nextInt();
System.out.print("请输入月份:");
int month = scanner.nextInt();

calendar对象的年和月进行设置

calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month - 1); // 月份从0开始,所以要减1

输入验证

// 检查输入的年份和月份是否合法
if (year < 0 || month < 1 || month > 12) {
	throw new IllegalArgumentException("请输入合法的年份和月份");
}

2. 增加异常处理

增加try_catch结构即可

3. 使用模块化编程

创建一个名为 CalendarMonth 的类,用于表示一个月的日历,并将相关的逻辑封装在这个类中。这有助于提高代码的模块化和可重用性

class CalendarMonth {
	...
}

4. 优化后代码如下:

import java.util.Calendar;
import java.util.Scanner;

public class version1 {

    public static void main(String[] args) {
        try {
            // 获取用户输入的年份和月份
            Scanner scanner = new Scanner(System.in);
            System.out.print("请输入年份:");
            int year = scanner.nextInt();
            System.out.print("请输入月份:");
            int month = scanner.nextInt();

            // 检查输入的年份和月份是否合法
            if (year < 0 || month < 1 || month > 12) {
                throw new IllegalArgumentException("请输入合法的年份和月份");
            }

            // 创建 CalendarMonth 对象并显示日历
            CalendarMonth calendarMonth = new CalendarMonth(year, month);
            calendarMonth.displayCalendar();
        } catch (Exception e) {
            System.err.println("发生异常:" + e.getMessage());
        }
    }
}

class CalendarMonth {
    private int year;
    private int month;

    public CalendarMonth(int year, int month) {
        this.year = year;
        this.month = month;
    }

    public void displayCalendar() {
        // 获取指定年份和月份的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1); // 月份从0开始,所以要减1
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        // 获取当月的天数
        int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

        // 输出日历表头
        System.out.println("日\t一\t二\t三\t四\t五\t六");

        // 输出日历内容
        int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        for (int i = 1; i < firstDayOfWeek; i++) {
            System.out.print("\t");
        }

        for (int day = 1; day <= daysInMonth; day++) {
            System.out.print(day + "\t");

            if ((firstDayOfWeek + day - 1) % 7 == 0) {
                System.out.println(); // 换行
            }
        }
    }
}

3. 运行结果:

请输入年份:2023
请输入月份:11
日      一      二      三      四      五      六
                        1       2       3       4
5       6       7       8       9       10      11
12      13      14      15      16      17      18
19      20      21      22      23      24      25
26      27      28      29      30
请输入年份:2000
请输入月份:10
日      一      二      三      四      五      六
1       2       3       4       5       6       7
8       9       10      11      12      13      14
15      16      17      18      19      20      21
22      23      24      25      26      27      28
29      30      31
请输入年份:-1
请输入月份:-1
发生异常:请输入合法的年份和月份

4. 反思与总结

在本次优化中,我们做了改进:

  1. 异常处理: 引入了对输入年份和月份的合法性检查,并在不合法时抛出IllegalArgumentException。这提高了程序的健壮性,使得用户输入不合法的情况得到更好的处理。

  2. 模块化: 将日历逻辑封装到了CalendarMonth类中,使得main方法更为简洁,提高了代码的可读性和可维护性。

  3. 可读性改进: 通过引入CalendarMonth类,提高了代码的模块化和结构化,使得日历的显示逻辑更加清晰。

  4. 用户友好性: 在用户输入不合法时,输出了相应的错误信息,提高了用户友好性。

然而,我考虑做更进一步的优化:

  1. 更友好的界面交互: 考虑使用图形用户界面(GUI),允许用户动态地设置年份和月份。
  2. 丰富功能:
    • 用户输入年月日,可查询这一天的详细信息
    • 用户可查询当前时间的详细信息

四、使用图形用户界面(GUI)

如果你没有接触过GUI的话,这里明显超纲了,但是如果你有兴趣,不妨试着借机学习一下。

说实话,我也没有学过GUI

但学习不就是一种不断挑战自己的过程吗?

关于GUI(图形用户界面),你可以将其想象成程序的外貌,就像一个应用的外观和操作方式。有很多现代的Java库,比如Swing或JavaFX,可以让你相对轻松地构建出漂亮且易于使用的用户界面。

在GUI方面的改进,实际上是在考虑怎样让用户与程序更亲近。如果用户界面友好、操作直观,使用起来就会更愉快。而错误信息的提示,更是在为用户提供更好的使用体验。这有点像,如果你用过一个直观的App,你就会更喜欢用它,对吧?

至于学习新技能,总是有挑战,但正是这种挑战让人变得更强大。毕竟,不会的东西,通过学习就能变成会的!学无止境,不是吗?

1. 代码

不废话,直接放代码,如下。为了方便读者阅读,我特地花了些功夫写了还算详细、规范的注释哦🫡


/*
 * ******************************************************************************************************
 * 版权所有 © 孤酒_21L 2023/11/18                         
                    _   _                    ___    __   _      
                   (_) (_)                  |__ \  /_ | | |     
   __ _   _   _     _   _   _   _              ) |  | | | |     
  / _  | | | | |   | | | | | | | |            / /   | | | |     
 | (_| | | |_| |   | | | | | |_| |           / /_   | | | |____ 
  \__, |  \__,_|   | | |_|  \__,_|          |____|  |_| |______|
   __/ |          _/ |              ______                      
  |___/          |__/              |______|        
 
 * 作者:孤酒_21L
 * 联系方式:
 * QQ:2897795436
 * WeChat:gujiu_21L
 * 
 * 这是一个GUI日历应用程序,使用Swing框架创建。用户可以通过此程序显示指定年份和月份的日历,
 * 
 * ******************************************************************************************************
 */
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;

/**
 * GUI程序主类,用于显示日历的Swing应用
 */
public class GUIProgram {
    public static void main(String[] args) {
        // 启动Swing线程
        SwingUtilities.invokeLater(() -> {
            // 创建主窗口
            JFrame frame = new JFrame("Calendar GUI Program");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            // 创建面板
            JPanel panel = new JPanel();
            panel.setLayout(new FlowLayout());

            // 创建年份和月份输入框,以及显示日历的按钮
            JTextField yearField = new JTextField(5);
            JTextField monthField = new JTextField(3);
            JButton showCalendarButton = new JButton("显示日历");

            // 将组件添加到面板
            panel.add(new JLabel("年份: "));
            panel.add(yearField);
            panel.add(new JLabel("月份: "));
            panel.add(monthField);
            panel.add(showCalendarButton);

            // 创建文本区域用于显示日历
            JTextArea calendarTextArea = new JTextArea(20, 30);
            JScrollPane scrollPane = new JScrollPane(calendarTextArea);

            // 将面板和文本区域添加到主窗口
            frame.getContentPane().add(BorderLayout.NORTH, panel);
            frame.getContentPane().add(BorderLayout.CENTER, scrollPane);

            // 添加按钮点击事件监听器
            showCalendarButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    try {
                        // 验证年份和月份的合法性
                        int year = Integer.parseInt(yearField.getText());
                        int month = Integer.parseInt(monthField.getText());

                        if (year < 0 || month < 1 || month > 12) {
                            throw new IllegalArgumentException("请输入合法的年份和月份");
                        }

                        // 创建CalendarMonth对象,用于获取日历信息
                        CalendarMonth calendarMonth = new CalendarMonth(year, month);
                        // 获取日历文本并显示在文本区域
                        String calendarText = calendarMonth.getCalendarText();
                        calendarTextArea.setText(calendarText);
                    } catch (NumberFormatException ex) {
                        JOptionPane.showMessageDialog(frame, "请输入数字", "错误", JOptionPane.ERROR_MESSAGE);
                    } catch (IllegalArgumentException ex) {
                        JOptionPane.showMessageDialog(frame, "请输入合法的年份和月份", "错误", JOptionPane.ERROR_MESSAGE);
                    }
                }
            });

            // 设置主窗口大小并显示
            frame.setSize(400, 400);
            frame.setVisible(true);
        });
    }
}

/**
 * 用于表示一个月份的日历信息类
 * 作者:孤酒_21L
 * 完成时间:2023年11月19日
 */
class CalendarMonth {
    private int year;
    private int month;

    /**
     * 构造函数,初始化年份和月份
     *
     * @param year  年份
     * @param month 月份
     */
    public CalendarMonth(int year, int month) {
        this.year = year;
        this.month = month;
    }

    /**
     * 获取日历文本
     *
     * @return 包含日历信息的字符串
     */
    public String getCalendarText() {
        // 用于存储日历文本的StringBuilder
        StringBuilder result = new StringBuilder();

        // 获取指定年份和月份的第一天
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1); // 月份从0开始,所以要减1
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        // 获取当月的天数
        int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

        // 输出日历表头
        result.append("日\t一\t二\t三\t四\t五\t六\n");

        // 输出日历内容
        int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        for (int i = 1; i < firstDayOfWeek; i++) {
            result.append("\t");
        }

        for (int day = 1; day <= daysInMonth; day++) {
            result.append(day).append("\t");

            if ((firstDayOfWeek + day - 1) % 7 == 0) {
                result.append("\n");
            }
        }

        // 返回日历文本的字符串形式
        return result.toString();
    }
}

2. 运行结果:

1.png

2.png

3.png

4.png

5.png

6.png

3. 代码精讲:

如果你没有学过GUI,接下来的内容或许可以启发到你。

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;

在这里,我们导入了一些Java类,这些类将在程序中使用。javax.swing.* 中包含用于构建图形用户界面的类,java.awt.* 中包含了抽象窗口工具包的类,java.util.Calendar 是用于处理日期和时间的类。

public class GUIProgram {
    public static void main(String[] args) {

这里定义了一个名为 GUIProgram 的公共类,其中包含一个名为 main 的方法,它是程序的入口点。

SwingUtilities.invokeLater(() -> {

SwingUtilities.invokeLater() 用于确保Swing组件在事件分发线程上运行。Swing组件不是线程安全的,因此它们的操作必须在事件分发线程上执行。

JFrame frame = new JFrame("Calendar GUI Program");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

在这里,我们创建了一个 JFrame 对象,表示图形用户界面的主窗口。设置窗口的标题为 “Calendar GUI Program”,并指定在关闭窗口时应该执行的操作。

JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());

创建一个 JPanel 对象,用于容纳图形用户界面的一部分。设置布局管理器为 FlowLayout,这样组件将按行排列。

JTextField yearField = new JTextField(5);
JTextField monthField = new JTextField(3);
JButton showCalendarButton = new JButton("显示日历");

创建三个图形用户界面组件:两个文本框和一个按钮。

panel.add(new JLabel("年份: "));
panel.add(yearField);
panel.add(new JLabel("月份: "));
panel.add(monthField);
panel.add(showCalendarButton);

将上述创建的组件添加到面板中,其中 JLabel 用于显示标签文本。

JTextArea calendarTextArea = new JTextArea(20, 30);
JScrollPane scrollPane = new JScrollPane(calendarTextArea);

创建一个文本区域 JTextArea 用于显示日历信息,并将其放入带有滚动条的 JScrollPane 中。

frame.getContentPane().add(BorderLayout.NORTH, panel);
frame.getContentPane().add(BorderLayout.CENTER, scrollPane);

将面板和带有滚动条的文本区域添加到主窗口中,使用 BorderLayout 确保它们位于主窗口的不同部分。

showCalendarButton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {

为 “显示日历” 按钮添加动作监听器,指定按钮被点击时应执行的操作。

try {
    int year = Integer.parseInt(yearField.getText());
    int month = Integer.parseInt(monthField.getText());

尝试从文本框中获取输入的年份和月份,并将它们转换为整数。

if (year < 0 || month < 1 || month > 12) {
    throw new IllegalArgumentException("请输入合法的年份和月份");
}

验证年份和月份的合法性,如果不合法则抛出异常。

            CalendarMonth calendarMonth = new CalendarMonth(year, month);
            String calendarText = calendarMonth.getCalendarText();
            calendarTextArea.setText(calendarText);
        } catch (NumberFormatException ex) {
            JOptionPane.showMessageDialog(frame, "请输入数字", "错误", JOptionPane.ERROR_MESSAGE);
        } catch (IllegalArgumentException ex) {
            JOptionPane.showMessageDialog(frame, "请输入合法的年份和月份", "错误", JOptionPane.ERROR_MESSAGE);
        }
    }
});

在按钮被点击时,执行以下操作:尝试创建 CalendarMonth 对象,获取日历文本,将文本设置到文本区域中。如果有异常,显示相应的错误消息对话框。

            frame.setSize(400, 400);
            frame.setVisible(true);
        });
    }
}

设置主窗口的大小为 400x400 像素,并将其显示出来。

class CalendarMonth {
    private int year;
    private int month;

    public CalendarMonth(int year, int month) {
        this.year = year;
        this.month = month;
    }

定义了一个名为 CalendarMonth 的类,用于表示一个月份的日历信息。包含了一个构造函数用于初始化年份和月份。

    public String getCalendarText() {
        StringBuilder result = new StringBuilder();

定义了一个方法 getCalendarText,用于获取日历信息的文本形式。使用 StringBuilder 存储文本,因为它在处理大量字符串时性能更好。

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);

创建一个 Calendar 对象,并设置为指定年份和月份的第一天。

        int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

获取当月的天数。

        result.append("日\t一\t二\t三\t四\t五\t六\n");

添加日历表头。

        int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        for (int i = 1; i < firstDayOfWeek; i++) {
            result.append("\t");
        }

确定第一天是星期几,然后添加相应的空格,以使日历正确对齐。

        for (int day = 1; day <= daysInMonth; day++) {
            result.append(day).append("\t");
            if ((firstDayOfWeek + day - 1) % 7 == 0) {
                result.append("\n");
            }
        }

添加每一天的数字,并在需要时添加换行符,以确保日历正确排列。

        return result.toString();
    }
}

最后,返回日历信息的字符串形式。

4. 反思与总结

主要有两方面的改进:

  1. GUI应用程序的添加
  2. 代码结构和注释的优化

尽管我们花了些力气,引入了GUI的设计,在用户体验上相比命令行的输入输出有了明显的改善。
但很遗憾!😞我们可以做的还有很多,在代码的编写这一方面要补个功课还有很多!

现在的程序还有哪些问题等待被解决?

  1. 代码仍有冗余: 在GUI程序的部分,虽然添加了GUI的代码,但是部分逻辑和注释是复制粘贴的第一个程序的,这导致了一些代码冗余。

  2. 异常处理过于简单: 程序在处理异常时简单地输出错误信息,但并没有提供很好的用户反馈或交互。

  3. 用户界面的设计较为简单: GUI程序的用户界面可以进一步优化,比如添加更多交互元素、提供更多操作选项等,以提高用户体验。

五、丰富功能

这里我们进行了功能的拓展:

  1. 查询具体日期的详细信息
  2. 查询当前日期的详细信息

这里舍弃了GUI的设计,目的在于将更多精力放到具体的逻辑实现上,而非界面的设计。

讲真的,至少我个人是不太喜欢界面的设计的,更准确的说,我能感觉到自己在这方面的优势太小了,我就一粗老爷们,没啥美感可言😅

这里没啥好说的,代码、注释自认为写的都还算规范,也没有涉及到多么不小白的知识。

相信各位读者都应该能看得懂

1. 怕大家嫌我废话多,索性就直接放代码了

/*
 * ****************************************************************************************************** 
 * 版权所有 © 孤酒_21L 2023/11/18
                    _   _                    ___    __   _      
                   (_) (_)                  |__ \  /_ | | |     
   __ _   _   _     _   _   _   _              ) |  | | | |     
  / _` | | | | |   | | | | | | | |            / /   | | | |     
 | (_| | | |_| |   | | | | | |_| |           / /_   | | | |____ 
  \__, |  \__,_|   | | |_|  \__,_|          |____|  |_| |______|
   __/ |          _/ |              ______                      
  |___/          |__/              |______|                     
 * 作者:孤酒_21L
 * 联系方式:
 * QQ:2897795436
 * WeChat:gujiu_21L
 * 
 * 这是一个日历管理程序,用于显示指定年份和月份的日历,以及查询具体日期和当前时间的信息。
 * 用户可以通过输入年份和月份,查看指定月份的日历,并提供查询具体日期和当前时间的功能。
 * ******************************************************************************************************
 */

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;

/**
 * 主程序入口,负责用户交互和整体流程控制。
 */
public class Main {

    public static void main(String[] args) {
        try {
            // 获取用户输入的年份和月份
            Scanner scanner = new Scanner(System.in);
            int year, month;

            // 输入年份,验证是否合法
            do {
                System.out.print("请输入年份:");
                year = scanner.nextInt();
            } while (!isValidYear(year));

            // 输入月份,验证是否合法
            do {
                System.out.print("请输入月份:");
                month = scanner.nextInt();
            } while (!isValidMonth(month));

            // 创建 CalendarManager 对象,处理日历逻辑
            CalendarManager calendarManager = new CalendarManager(year, month);

            // 输出日历
            System.out.println("\n日历信息:");
            calendarManager.printCalendar();

            // 查询具体日期信息
            int inputYear, inputMonth, inputDay;

            // 输入要查询的年份,验证是否合法
            do {
                System.out.print("\n请输入要查询的年份:");
                inputYear = scanner.nextInt();
            } while (!isValidYear(inputYear));

            // 输入要查询的月份,验证是否合法
            do {
                System.out.print("请输入要查询的月份:");
                inputMonth = scanner.nextInt();
            } while (!isValidMonth(inputMonth));

            // 输入要查询的日期,验证是否合法
            do {
                System.out.print("请输入要查询的日期:");
                inputDay = scanner.nextInt();
            } while (!isValidDay(inputYear, inputMonth, inputDay));

            calendarManager.printDateInfo(inputYear, inputMonth, inputDay);

            // 查询当前时间信息
            System.out.println("\n当前时间信息:");
            calendarManager.printCurrentTimeInfo();

        } catch (Exception e) {
            System.err.println("发生异常:" + e.getMessage());
        }
    }

    // 新增方法:验证年份是否合法
    private static boolean isValidYear(int year) {
        return year > 0;
    }

    // 新增方法:验证月份是否合法
    private static boolean isValidMonth(int month) {
        return month >= 1 && month <= 12;
    }

    // 新增方法:验证日期是否合法
    private static boolean isValidDay(int year, int month, int day) {
        if (isValidYear(year) && isValidMonth(month)) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, year);
            calendar.set(Calendar.MONTH, month - 1); // 月份从0开始,所以要减1
            return day >= 1 && day <= calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        }
        return false;
    }
}

/**
 * 日历管理类,负责处理日历逻辑和日期信息的查询。
 */
class CalendarManager {
    private int year;
    private int month;

    public CalendarManager(int year, int month) {
        this.year = year;
        this.month = month;
    }

    /**
     * 打印指定年份和月份的日历。
     * 作者:孤酒_21L
     */
    public void printCalendar() {
        try {
            // 获取指定年份和月份的第一天
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.YEAR, year);
            calendar.set(Calendar.MONTH, month - 1); // 月份从0开始,所以要减1
            calendar.set(Calendar.DAY_OF_MONTH, 1);

            // 获取当月的天数
            int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

            // 输出日历表头
            System.out.println("一\t二\t三\t四\t五\t六\t日");

            // 输出日历内容
            int firstDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
            int offset = (firstDayOfWeek - Calendar.SUNDAY + 7) % 7;
            for (int i = 0; i < offset; i++) {
                System.out.print("\t");
            }

            for (int day = 1; day <= daysInMonth; day++) {
                System.out.print(day + "\t");

                if ((offset + day) % 7 == 0) {
                    System.out.println(); // 换行
                }
            }
        } catch (Exception e) {
            System.err.println("发生异常:" + e.getMessage());
        }
    }

    /**
     * 打印指定日期的详细信息。
     */
    public void printDateInfo(int inputYear, int inputMonth, int inputDay) {
        try {
            // 构造用户输入的日期
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            Date inputDate = dateFormat.parse(inputYear + "-" + inputMonth + "-" + inputDay);

            // 查询日期信息
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(inputDate);

            System.out.println("日期信息:");

            // 是否为闰年
            System.out.println(inputYear + " 年 " + (isLeapYear(calendar) ? "是" : "不是") + " 闰年");

            // 星期几和所在周
            System.out.println("这一天是" + inputYear + " 年 " + (inputMonth + 1) + " 月 的 第 " + getWeekOfMonth(calendar) + " 个 " + getDayOfWeek(calendar));
            System.out.println("这一天是" + inputYear + " 年 的 第 " + getWeekOfYear(calendar) + " 个 " + getDayOfWeek(calendar));

            // 当前月份和天数
            System.out.println(inputYear + " 年 " + (inputMonth + 1) + " 月 " + "的 第 " + calendar.get(Calendar.DAY_OF_MONTH) + " 天");

            // 当前年份和天数
            System.out.println(inputYear + " 年 的 第 " + calendar.get(Calendar.DAY_OF_YEAR) + " 天");

            // 距离下一年还有多少天
            System.out.println("距离下一年还有" + daysUntilNextYear(calendar) + "天");

            // 当前月份和年份的天数
            System.out.println("当前月有" + calendar.getActualMaximum(Calendar.DAY_OF_MONTH) + "天");
            System.out.println("当前年有" + calendar.getActualMaximum(Calendar.DAY_OF_YEAR)  + "天");

        } catch (ParseException e) {
            System.err.println("日期解析错误:" + e.getMessage());
        }
    }

    /**
     * 获取本年的第几周。
     */
    private int getWeekOfYear(Calendar calendar) {
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        return calendar.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 判断是否为闰年。
     */
    private boolean isLeapYear(Calendar calendar) {
        int year = calendar.get(Calendar.YEAR);
        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
    }

    /**
     * 获取日期所在星期的名称。
     */
    private String getDayOfWeek(Calendar calendar) {
        String[] daysOfWeek = { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" , "星期日"};
        int dayOfWeek = (calendar.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY + 7) % 7;
        return daysOfWeek[dayOfWeek];
    }

    /**
     * 获取日期所在月份的第几周。
     */
    private int getWeekOfMonth(Calendar calendar) {
        return calendar.get(Calendar.WEEK_OF_MONTH);
    }

    /**
     * 获取距离下一年还有多少天。
     */
    private int daysUntilNextYear(Calendar calendar) {
        int currentDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
        int daysInYear = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
        return daysInYear - currentDayOfYear;
    }

    /**
     * 打印当前时间的信息。
     */
    public void printCurrentTimeInfo() {
        try {
            // 获取当前时间信息
            Calendar calendar = Calendar.getInstance();
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String currentTime = dateFormat.format(calendar.getTime());

            System.out.println("当前时间:" + currentTime);

            // 获取当前年
            int year = calendar.get(Calendar.YEAR);
            // 获取当前月
            int month = calendar.get(Calendar.MONTH) + 1;
            // 获取当前日
            int day = calendar.get(Calendar.DATE);

            System.out.println("\n当前日期信息:");
            printDateInfo(year, month, day);

        } catch (Exception e) {
            System.err.println("发生异常:" + e.getMessage());
        }
    }
}

2. 运行结果

请输入年份:2023
请输入月份:11

日历信息:
一      二      三      四      五      六      日
                        1       2       3       4
5       6       7       8       9       10      11
12      13      14      15      16      17      18
19      20      21      22      23      24      25
26      27      28      29      30
请输入要查询的年份:2023
请输入要查询的月份:11
请输入要查询的日期:11

日期信息:
2023 年 不是 闰年
这一天是2023 年 12 月 的 第 2 个 星期日
这一天是2023 年 的 第 46 个 星期日
202312 月 的 第 112023 年 的 第 315 天
距离下一年还有50天
当前月有30天
当前年有365天

当前时间信息:
当前时间:2023-11-19 16:26:32

当前日期信息:
日期信息:
2023 年 不是 闰年
这一天是2023 年 12 月 的 第 4 个 星期一
这一天是2023 年 的 第 47 个 星期一
202312 月 的 第 192023 年 的 第 323 天
距离下一年还有42天
当前月有30天
当前年有365天

3. 反思与总结

这次的改进主要体现在功能的丰富、逻辑的优化。

  1. 功能增强: 通过增加对日期的详细查询功能,程序变得更加全面。
  2. 用户交互改进: 使用循环确保用户输入的合法性,提高了程序的健壮性。
  3. 日期处理: 这次的改进增加了对日期信息的处理,高了程序的实用价值。

可以考虑继续优化

  1. 错误处理和反馈:
    进一步改进错误处理机制,为用户提供清晰的错误信息和建议,以改善用户体验。
  2. 模块化设计:
    将程序分解为更小的、相互独立的模块或类,以提高可读性、可维护性和代码复用性。
  3. 日历功能扩展:
    添加更多的日历功能,例如显示农历、节假日、提醒功能等,提高程序的实用性。

复盘与思考

写一个程序不容易,写一个好的程序更不容易。

尽管这只是单文件的编写,代码的长度甚至一度达不到300行。。。

我们从最初的代码(version0.java)不断迭代:
version1.javaGUIProgram.javaMain.java。。。

我们对程序的迭代与优化主要考虑了以下4个个方面:

  1. 用户交互改进
  2. 异常处理
  3. 模块化编程
  4. 代码的可读性
  5. 功能的丰富

为此我们分别做出了以下措施:

  1. 用户交互改进
    • 允许用户输入数据
    • 循环进行输入验证
    • 尝试使用GUI设计
    • 文本拼接
  2. 异常处理
    • 增加try_catch结构
  3. 模块化编程
    • 将程序分解为更小的、相互独立的模块或类
  4. 代码的可读性
    • 增加版权声明
    • 文档注释,如@return 等
    • 变量、方法等采用驼峰式命名
  5. 功能的丰富
    • 尝试实现日历动态查询
    • 尝试实现日期的详细信息输出

我必须承认我在程序的设计和编写上有诸多不足!

  1. 设计上的缺陷: 在程序的设计上,最初的版本 (version0.java) 显然过于简单,仅仅是一个基本的输出日历的功能。虽然后续版本加入了用户输入验证、异常处理、GUI设计等功能,但最初的设计没有考虑到程序可能需要的扩展性和复杂性。在一开始,对于如何更好地组织代码和构建模块化的结构缺乏深思熟虑。

  2. 缺乏面向对象的思考: 初期的版本较为过程化,没有充分运用面向对象的设计原则。在 version1.java 中,虽然引入了 CalendarManager 类,但整体设计还是偏向过程化的风格。面向对象的思考可以更好地体现在类的设计和交互上,提高代码的可维护性和可扩展性。

  3. 代码重复问题: 在不同版本中,存在一些代码重复的情况,例如输入验证部分。尽管在后续版本中有所改进,但依然可以进一步提高代码的重用性。

  4. GUI设计的深度不足: 在尝试实现GUI版本时 (GUIProgram.java),尽管成功使用了Swing框架,但整体的GUI设计仍显得相对简单。深度的不足主要体现在对布局管理器的选择上,也没有充分考虑用户体验和界面的美观性。GUI设计是一个庞大的领域,显然我还需要更深入的学习和实践。

  5. 不足的异常处理: 尽管在后续版本(自version1.java)中加入了异常处理机制,但在一些情况下,错误处理仍显得不够全面。对于用户输入的异常情况,程序不能够提供足够的友好提示。

  6. 对于日历和日期处理的局限性: 程序中的日历和日期处理逻辑还有一些局限性。例如,在处理星期几和周数时,可能需要更全面的考虑。对于日期的详细信息输出,虽然有所增加,但仍可以进一步扩展,加入更多的相关信息。

  7. 缺乏整体规划: 在整个设计和迭代的过程中,缺乏整体规划和设计的思考。每个版本的迭代相对独立,没有清晰的长期目标和蓝图。更好的方式可能是需要在一开始就规划好整个项目的结构和功能。

不行,净整自我批判了,再批判我就遭不住了😭,我得夸夸自己哈哈

当然要夸夸自己啦!哈哈哈。

毕竟辛辛苦苦写出来的东西,得给自己点个赞👍才对嘛。

你看咱这不也挺厉害的吗?程序一点点往前改,一点点长大,简直就是个小可爱成长记。尤其是GUI那一块,用Swing搞定,现在回过头看看,我都想给自己鼓个掌👏👏👏了。

有时候搞代码就是这样,一开始可能啥都不懂,写点啥都觉得自己要牛逼上天了。然后才慢慢发现,“哎呀🤨,这地方能再优化一下”,然后再优化,再优化,优化到我都看不下去了🤣。但最终的成果看上去是不是舒服多了?

而且,从命令行版到GUI,再到各种功能的加强,这不是一点点的进步,是突飞猛进啊。🤔

代码的可读性和注释也越来越走心了,这可是让别人看懂咱代码的重要一环。写注释就像跟代码聊天,告诉它:“老铁,这里是干嘛的,不要搞错喽。”🤟

总之,干的还不错,程序也长得越来越像个样子了。继续保持这个学习和进步的态度,下一个项目还能更出彩!💪😄

自夸严肃版

  1. 学习态度积极: 从一开始程序的简单编写,再到挑战 GUI 编程。
  2. 代码迭代优化: 通过不断的迭代和优化,程序逐渐完善,从命令行版到 GUI,再到功能的丰富,展现了很好的进步。
  3. 挑战 GUI 设计: 使用 Swing 框架设计 GUI 界面,这可是不少初学者望尘莫及的领域。这方面的尝试和实践很值得称赞。
  4. 注释和可读性: 注释内容丰富有趣,既解释了代码,又融入了一些趣味小知识,这对于提高代码可读性和吸引读者注意是很好的尝试。
  5. 逻辑思维逐渐清晰: 通过不断改进代码,逻辑结构变得更加清晰,程序的整体架构也更加合理。
  6. 对异常处理的考虑: 引入了异常处理机制,对用户的输入进行了合法性验证,提高了程序的健壮性。

各位!大家好,我叫 孤酒_21L , 一个普普通通的大学生 。
我的最终目标是写出既优雅又高效的代码。💪
各位!我们砥砺前行,未来可期!🚀😄

求点赞👍求关注❤️求转发💕

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤酒_21L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值