徒手撸一个记账本(附源码)

简介: 徒手撸一个记账本(附源码)

前言

之前已经写过关于 学生成绩管理系统 以及 点菜系统 的文章,大家如果感兴趣,可以点击各自的传送门去看看呀!


接下来开始我们今天的正题,我们日常生活中,想必有很多人都有记账的习惯,那今天,我们就来看看,如何设计并实现一个记账本。


需求分析

打开我们手机里的记账本,可以发现主要提供如下几个功能:


添加账目

删除账目

修改账目

查询账目

查询所有账目

按时间区间查询

按账目类型查询

退出记账本


image.png

功能预览及代码实现

主菜单

主菜单中,主要用于打印提示我们进行选择,然后根据我们的输入再进入不同的子功能模块中。

  • 预览

image.png

  • 代码实现

代码实现很简单,只需要打印出提示信息即可,之后后续输入以及进入不同子功能模块,我们可以使用 switch 来进行选择。

package com.cunyu;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
/**
 * Created with IntelliJ IDEA.
 *
 * @author : 村雨
 * @version : 1.0
 * @project : Java 实战
 * @package : com.cunyu
 * @className : MainApp
 * @createTime : 2021/8/1 7:22
 * @email : 747731461@qq.com
 * @公众号 : 村雨遥
 * @website : https://cunyu1943.github.io
 * @description :
 */
public class MainApp {
    public static void main(String[] args) {
        boolean flag = true;
        while (flag) {
            System.out.println("----------欢迎使用记账系统--------");
            System.out.println("----------【1】添加账务----------");
            System.out.println("----------【2】删除账务----------");
            System.out.println("----------【3】修改账务----------");
            System.out.println("----------【4】查询账务----------");
            System.out.println("----------【0】退出-------------");
            System.out.println("请输入功能序号【0-4】");
        }
        System.out.println("退出系统,期待下次见面 ~");
    }
}

添加账目

当我们需要添加一笔新的账目时,此时就可以进入 添加账目 子模块,这里的功能主要是根据我们自己输入的 ID、类别、账户、类型、金额、时间以及备注将其添加到我们的总账目列表中进行汇总。

  • 预览

33.png代码实现

要实现添加功能也很简单,根据我们的输入,我们利用账目类的构造函数创建一个对象,然后将其加入总账目列表当中就可以了。


public void add(List<Bill> billList, int id, String category, String account, String type, double amount, String time, String desc) {

   //创建一个账单对象,然后将其加入列表

   Bill bill = new Bill(id, category, account, type, amount, time, desc);

   billList.add(bill);

}


删除账目

假如我们的账目要公开给别人看,而自己有的账目又不想让别人看到,咋办呢?很简单!我们只需要将这笔账目干掉即可!这里我们只要输入我们所要删除的账单 ID,然后将其从总账目列表中删除即可。


预览


33.png代码实现

要删除我们的账目,只需要根据我们输入的账单 id,找到对应 id 的账目,然后将其删除即可,这里之所以没有使用 remove(index) 的方式,是因为我们的 id 是自己输入的,这其实是不规则的,如果我们使用 remove(index) 的方式,就有可能导致越界的问题。


public void del(List<Bill> billList, int id) {
    //找到对应 id 的账单,并将其删除
    for (Bill bill : billList) {
        if (bill.getId() == id) {
            billList.remove(bill);
        }
    }
}

修改账目

我们偷偷拿了私房钱买了猛男必备显卡(RTX 3090)想趁空了打打游戏,遇到老婆查账时,这时候可不能慌,我们只需要把账单偷梁换柱,改换成其他东西就可以,而且此事神不知鬼不觉,美滋滋呀!

  • 预览33.png代码实现

利用代码实现也很简单,找到对应 ID 的账单,然后重新输入账单各个细节进行修改即可!

public void modify(List<Bill> billList) {
    Scanner scanner = new Scanner(System.in);
    System.out.println("输入你要修改对应账务的 ID");
    int id = scanner.nextInt();
    System.out.println("请输入修改后的账务类别");
    String category = scanner.next();
    System.out.println("请输入修改后的账户");
    String account = scanner.next();
    System.out.println("请输入修改后的类型(收入/支出)");
    String type = scanner.next();
    System.out.println("请输入修改后的金额");
    double amount = scanner.nextDouble();
    System.out.println("请输入修改后的时间");
    String time = scanner.next();
    System.out.println("请输入修改后的备注");
    String description = scanner.next();
    //找到对应 id 的账单,然后修改对应信息
    for (Bill bill : billList) {
        if (bill.getId() == id) {
            bill.setCategory(category);
            bill.setAmount(amount);
            bill.setAccount(account);
            bill.setTime(time);
            bill.setType(type);
            bill.setDesc(description);
        }
    }
}

查询账目

查询账目这里,我们又分为 3 个不同的功能,既可以查看所有账单,也可以根据我们所输入的时间区间进行筛选,最后,还能够根据我们的输入查询出收入和支出的详细情况。

查询所有账目

  • 预览

image.png代码实现

查询所有账单很简单,只需要遍历我们总账单列表即可。


public void queryAll(List<Bill> billList) {

   System.out.println("ID\t\t类别\t\t\t账户\t\t类型\t\t金额\t\t\t时间\t\t\t\t备注");

   for (Bill bill : billList) {

       System.out.println(bill.getId() + "\t\t" + bill.getCategory() + "\t\t" + bill.getAccount() + "\t\t" + bill.getType() + "\t\t" + bill.getAmount() + "\t\t" + bill.getTime() + "\t\t" + bill.getDesc());

   }

}


按时间区间查询

预览


image.png

  • 代码实现

按照时间跨度来查询稍微要麻烦一些,这里要处理两个输入,一个是开始时间,一个是结束时间,我们需要将账单的时间和这两个时间进行比较,筛选出介于这两者之间的账单。所以这里要涉及到 Date 类,然后就是如何从总账单列表中过滤出满足时间跨度的账单。

public void queryByTime(List<Bill> billList, String startTime, String endTime) {
    // 时间格式化
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    List<Bill> bills = billList.stream().filter(bill -> {
        String tmpTime = bill.getTime();
        try {
            // 将输入的时间字符串转换为格式化的 Date 类型
            Date tmpDate = simpleDateFormat.parse(tmpTime);
            Date startDate = simpleDateFormat.parse(startTime);
            Date endDate = simpleDateFormat.parse(endTime);
            // 将介于开始时间和结束时间的账单进行过滤
            if (tmpDate.before(endDate) && tmpDate.after(startDate)) {
                return true;
            }
        } catch (ParseException parseException) {
            parseException.printStackTrace();
        }
        return false;
        //    将其转换为列表
    }).collect(Collectors.toList());
    queryAll(bills);
}

按类型查询

  • 预览

image.png

  • 代码实现

这里按类型查询其实就是在查询所有账单的基础上加上一个限制条件,只要其类型等于我们的输入即可,这里我写了两种筛选的方法。一种是直接使用 if 语句进行过滤,而另一种则是同按时间跨度一样使用集合的 Stream 流来进行过滤。

public void queryByType(List<Bill> billList, String type) {
    //1. 第一种方式,利用条件判断
    //for (Bill bill : billList) {
    //    if (bill.getType().equals(type)) {
    //        System.out.println(bill.getId() + "\t\t" + bill.getCategory() + "\t\t" + bill.getAccount() + "\t\t" + bill.getType() + "\t\t" + bill.getAmount() + "\t\t" + bill.getTime() + "\t\t" + bill.getDesc());
    //    }
    //}
    //2. 第二种方式,利用集合 Stream 流
    List<Bill> bills = billList.stream().filter(bill -> {
        String tmpType = bill.getType();
        return tmpType.equals(type);
    }).collect(Collectors.toList());
    queryAll(bills);
}

image.png代码实现

在主菜单中,我们已经设置了一个标志位 flag,当 flag 为 true 时,我们每完成一项功能则循环打印主菜单在控制台中,而如果我们想要退出系统,只需要将标志位 flag 设置为 false 即可,此时不满足 while 循环的条件,所以跳出循环,因此退出系统的关键在于标志位状态的转换。


case "0":

   flag = false;

   break;


整体程序

将各个子模块功能实现之后,剩下的就是整合工作了,最后得到我们最后的总体程序结构如下,主要代码均位于 com.cunyu 包下,然后分别是:


实体类 Bill

接口类 IBill

主程序 MainApp


image.png总结

好了,以上就是我们简单的记账本的实现了。实现的功能比较简陋,程序的健壮性也不够强,还有很大的优化空间。大家如果感兴趣或者有优化的地方,欢迎到本设计的 Github 仓库地址:https://github.com/cunyu1943/java-in-actions 提交 issue。当然了,如果你只是需要用来简单的做个示例,也可以自取。


最后,如果本文对大家有用的话,希望给我一个⭐ star,满足一下我的虚荣心呀 ~ 🙊🙊🙊



目录
相关文章
|
移动开发 自然语言处理 小程序
分享88个企业政府PHP源码,总有一款适合你
分享88个企业政府PHP源码,总有一款适合你
827 2
|
人工智能 监控 安全
员工使用第三方AI办公的风险与解决方案:从三星案例看AI的数据防泄漏
生成式AI提升办公效率,也带来数据泄露风险。三星、迪士尼案例揭示敏感信息外泄隐患。AI-FOCUS团队建议构建“流式网关+DLP”防护体系,实现分级管控、全程审计,平衡安全与创新。
|
存储 人工智能 API
RAG:让AI不再胡说八道的秘密武器
想象一下,你的AI助手突然变成了一个什么都知道的专家,不再胡编乱造,而是有理有据地回答你的问题。这不是科幻小说,这就是RAG技术的魔力!让我们一起探索如何让AI变得更聪明、更可靠的奥秘。
654 0
|
10月前
|
存储 弹性计算 人工智能
2026阿里云服务器租用价格与计费指南:新购、续费、升级活动报价全解析
阿里云服务器凭借弹性伸缩、安全可靠的特性,覆盖个人开发、企业业务及高性能计算等多场景需求。其产品体系主要包含轻量应用服务器、云服务器 ECS 及 GPU 服务器三类,不同机型在配置、定价及适用场景上各有侧重,同时通过差异化的计费模式与优惠政策,满足不同用户的成本控制需求。本文将从各类型服务器的配置规格、价格体系(年付、月付、按小时计费)、续费政策及附加资源(带宽、存储)定价展开详细说明,为用户提供清晰的成本参考。
|
10月前
|
安全 前端开发 NoSQL
【RuoYi-SpringBoot3-Pro】: 三级等保安全配置
RuoYi-SpringBoot3-Pro 内置三级等保安全配置,涵盖密码策略、登录控制、IP 黑名单、会话管理等功能,通过动态参数实现无需重启的灵活管控,全面满足国家信息安全等级保护三级要求,提升系统安全性与合规性。
942 0
|
Java 编译器 程序员
java中重载和多态的区别
本文详细解析了面向对象编程中多态与重载的概念及其关系。多态是OOP的核心,分为编译时多态(静态多态)和运行时多态(动态多态)。编译时多态主要通过方法重载和运算符重载实现,如Java中的同名方法因参数不同而区分;运行时多态则依赖继承和方法重写,通过父类引用调用子类方法实现。重载是多态的一种形式,专注于方法签名的多样性,提升代码可读性。两者结合增强了程序灵活性与扩展性,帮助开发者更好地实现代码复用。
1064 0
|
存储 弹性计算 数据库
阿里云优惠券是什么?2024年阿里云优惠券领取地址链接和使用方法
阿里云优惠券为用户提供购云服务折扣。2024年可通过活动中获取各类云产品优惠。学生专享300元无门槛代金券,可用于购买ECS或轻量应用服务器。域名优惠口令(如com批量注册更享优惠)提供更多节省。领取阿里云超级红包(新人最高100元)。代金券可在查询,并在结算时选择使用。
2836 1
阿里云优惠券是什么?2024年阿里云优惠券领取地址链接和使用方法
|
Linux 网络安全 开发工具
Git学习笔记(一):基础与应用
本文档详细介绍了如何将本地项目关联到Gitee上的空仓库并上传代码,以及如何验证本机与Git服务器的SSH连接。同时,还概述了Git的基本概念、安装步骤、初始配置、常见命令及如何配置多个SSH-Key,适用于初学者快速上手Git操作。
649 51
Git学习笔记(一):基础与应用
|
数据采集 JSON 监控
怎么把抖音ip改到别的地方
动态IP修改技术原理及实现 一、技术背景与基本原理
|
存储 缓存 关系型数据库
图解MySQL【日志】——Redo Log
Redo Log(重做日志)是数据库中用于记录数据页修改的物理日志,确保事务的持久性和一致性。其主要作用包括崩溃恢复、提高性能和保证事务一致性。Redo Log 通过先写日志的方式,在内存中缓存修改操作,并在适当时候刷入磁盘,减少随机写入带来的性能损耗。WAL(Write-Ahead Logging)技术的核心思想是先将修改操作记录到日志文件中,再择机写入磁盘,从而实现高效且安全的数据持久化。Redo Log 的持久化过程涉及 Redo Log Buffer 和不同刷盘时机的控制参数(如 `innodb_flush_log_at_trx_commit`),以平衡性能与数据安全性。
1195 5
图解MySQL【日志】——Redo Log