Java实践之路(一):记账程序

概要

这是一个基于Java开发的个人记账管理系统,帮助用户记录日常收支情况,进行财务统计和分析。

项目结构设计

bash 复制代码
AccountingApp/
├── src/main/java/com/accounting/
│   ├── model/
│   │   ├── Transaction.java      # 交易记录实体类
│   │   └── Category.java         # 分类实体类
│   ├── service/
│   │   └── AccountingService.java # 记账业务逻辑
│   ├── util/
│   │   └── DateUtil.java         # 日期工具类
│   └── Main.java                 # 主程序入口

核心类实现

1. 交易记录实体类 (Transaction)

java 复制代码
package com.accounting.model;

import java.time.LocalDateTime;
import java.math.BigDecimal;

public class Transaction {
    private Long id;
    private LocalDateTime date;
    private BigDecimal amount;
    private String type; // "income" or "expense"
    private String category;
    private String description;
    
    // 构造函数
    public Transaction() {}
    
    public Transaction(BigDecimal amount, String type, String category, String description) {
        this.amount = amount;
        this.type = type;
        this.category = category;
        this.description = description;
        this.date = LocalDateTime.now();
    }
    
    // Getter和Setter方法
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public LocalDateTime getDate() { return date; }
    public void setDate(LocalDateTime date) { this.date = date; }
    
    public BigDecimal getAmount() { return amount; }
    public void setAmount(BigDecimal amount) { this.amount = amount; }
    
    public String getType() { return type; }
    public void setType(String type) { this.type = type; }
    
    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    @Override
    public String toString() {
        return String.format("[%s] %s: %.2f (%s) - %s", 
            date.toLocalDate(), type, amount, category, description);
    }
}

2. 记账业务服务类 (AccountingService)

java 复制代码
package com.accounting.service;

import com.accounting.model.Transaction;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class AccountingService {
    private List<Transaction> transactions;
    private Long nextId = 1L;
    
    public AccountingService() {
        this.transactions = new ArrayList<>();
    }
    
    /**
     * 添加收入记录
     */
    public void addIncome(BigDecimal amount, String category, String description) {
        Transaction transaction = new Transaction(amount, "收入", category, description);
        transaction.setId(nextId++);
        transactions.add(transaction);
        System.out.println("收入记录添加成功: " + transaction);
    }
    
    /**
     * 添加支出记录
     */
    public void addExpense(BigDecimal amount, String category, String description) {
        Transaction transaction = new Transaction(amount, "支出", category, description);
        transaction.setId(nextId++);
        transactions.add(transaction);
        System.out.println("支出记录添加成功: " + transaction);
    }
    
    /**
     * 获取所有交易记录
     */
    public List<Transaction> getAllTransactions() {
        return new ArrayList<>(transactions);
    }
    
    /**
     * 根据日期范围查询交易记录
     */
    public List<Transaction> getTransactionsByDateRange(LocalDate startDate, LocalDate endDate) {
        return transactions.stream()
            .filter(t -> !t.getDate().toLocalDate().isBefore(startDate))
            .filter(t -> !t.getDate().toLocalDate().isAfter(endDate))
            .collect(Collectors.toList());
    }
    
    /**
     * 计算总收入
     */
    public BigDecimal getTotalIncome() {
        return transactions.stream()
            .filter(t -> "收入".equals(t.getType()))
            .map(Transaction::getAmount)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    /**
     * 计算总支出
     */
    public BigDecimal getTotalExpense() {
        return transactions.stream()
            .filter(t -> "支出".equals(t.getType()))
            .map(Transaction::getAmount)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    /**
     * 计算账户余额
     */
    public BigDecimal getBalance() {
        return getTotalIncome().subtract(getTotalExpense());
    }
    
    /**
     * 按分类统计支出
     */
    public void printExpenseByCategory() {
        System.out.println("\n=== 支出分类统计 ===");
        transactions.stream()
            .filter(t -> "支出".equals(t.getType()))
            .collect(Collectors.groupingBy(
                Transaction::getCategory,
                Collectors.reducing(BigDecimal.ZERO, Transaction::getAmount, BigDecimal::add)))
            .forEach((category, amount) -> 
                System.out.println(category + ": " + amount));
    }
}

3. 主程序类 (Main)

java 复制代码
package com.accounting;

import com.accounting.model.Transaction;
import com.accounting.service.AccountingService;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Scanner;

public class Main {
    private static AccountingService accountingService = new AccountingService();
    private static Scanner scanner = new Scanner(System.in);
    
    public static void main(String[] args) {
        System.out.println("=== 个人记账软件 ===");
        
        while (true) {
            showMenu();
            int choice = scanner.nextInt();
            scanner.nextLine(); // 消费换行符
            
            switch (choice) {
                case 1:
                    addIncome();
                    break;
                case 2:
                    addExpense();
                    break;
                case 3:
                    showAllTransactions();
                    break;
                case 4:
                    showStatistics();
                    break;
                case 5:
                    showExpenseByCategory();
                    break;
                case 0:
                    System.out.println("感谢使用,再见!");
                    return;
                default:
                    System.out.println("无效选项,请重新选择");
            }
        }
    }
    
    private static void showMenu() {
        System.out.println("\n========== 菜单 ==========");
        System.out.println("1. 添加收入");
        System.out.println("2. 添加支出");
        System.out.println("3. 查看所有记录");
        System.out.println("4. 查看统计信息");
        System.out.println("5. 支出分类统计");
        System.out.println("0. 退出");
        System.out.print("请选择操作: ");
    }
    
    private static void addIncome() {
        System.out.print("请输入收入金额: ");
        BigDecimal amount = scanner.nextBigDecimal();
        scanner.nextLine(); // 消费换行符
        
        System.out.print("请输入收入分类 (如: 工资、奖金等): ");
        String category = scanner.nextLine();
        
        System.out.print("请输入备注: ");
        String description = scanner.nextLine();
        
        accountingService.addIncome(amount, category, description);
    }
    
    private static void addExpense() {
        System.out.print("请输入支出金额: ");
        BigDecimal amount = scanner.nextBigDecimal();
        scanner.nextLine(); // 消费换行符
        
        System.out.print("请输入支出分类 (如: 餐饮、交通、购物等): ");
        String category = scanner.nextLine();
        
        System.out.print("请输入备注: ");
        String description = scanner.nextLine();
        
        accountingService.addExpense(amount, category, description);
    }
    
    private static void showAllTransactions() {
        List<Transaction> transactions = accountingService.getAllTransactions();
        if (transactions.isEmpty()) {
            System.out.println("暂无交易记录");
            return;
        }
        
        System.out.println("\n=== 所有交易记录 ===");
        transactions.forEach(System.out::println);
    }
    
    private static void showStatistics() {
        System.out.println("\n=== 统计信息 ===");
        System.out.println("总收入: " + accountingService.getTotalIncome());
        System.out.println("总支出: " + accountingService.getTotalExpense());
        System.out.println("账户余额: " + accountingService.getBalance());
    }
    
    private static void showExpenseByCategory() {
        accountingService.printExpenseByCategory();
    }
}

生成可运行程序:使用 IntelliJ IDEA 中文版导出可执行 JAR

  1. 打开项目结构

    • 点击菜单栏 "文件" → "项目结构"
  2. 创建 Artifact

    • 在左侧面板选择 "工件" (Artifacts)
    • 点击 "+" 号 → "JAR" → "来自模块的依赖项"
    • 选择 com.accounting.Main 类作为主类
    • 点击 "确定"
  3. 构建 Artifact

    • 点击菜单栏 "构建" → "构建工件"
    • 选择刚刚创建的工件
    • 点击 "构建"
  4. 找到生成的 JAR 文件

    • 通常在项目根目录下的 out/artifacts 文件夹中

创建运行脚本

在生成的 JAR 文件同目录下创建 run.bat 文件:

batch 复制代码
@echo off
java -jar AccountingApp-1.0.0.jar
pause

这样用户就可以通过双击 run.bat 来运行你的记账软件了。

相关推荐
广州华水科技5 分钟前
北斗形变监测传感器在大坝安全监测中的应用与优势分析
前端
孔令飞11 分钟前
如何学习Go
前端
HUIBUR科技15 分钟前
AI 中枢,面向企业场景构建的 AI 智能体
前端·数据库·人工智能
随便写个软件32 分钟前
【新版本】EasyExplorer资源管理器 3.12.0——地址栏重要更新
运维·服务器·前端·everything·资源管理器
Jack N35 分钟前
【Strapi 系列之二】Collection / Single / Component 怎么选?Strapi 字段大全一篇讲透
前端·javascript·strapi
william_yangshun38 分钟前
WordCraft 观察:纯 Rust 重写文字处理器,把文档变成可编程对象
开发语言·后端·rust·文档自动化
hiahiahia12343 分钟前
Agent Tool 执行失败怎么办
服务器·前端
Java后端的Ai之路43 分钟前
09-React组件生命周期
前端·react.js·前端框架
IT_陈寒1 小时前
SpringBoot开发实战:从入门到精通
前端·人工智能·后端
乘风gg1 小时前
一个人一个月合并 2500 PRs 的秘密是什么?
前端·ai编程·claude