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 来运行你的记账软件了。

相关推荐
有意义8 小时前
Spring Boot 项目中部门查询功能实现与依赖注入优化
后端·设计模式
爱编码的傅同学8 小时前
【HTML教学】成为前端大师的入门教学
前端·html
秋枫968 小时前
使用React Bootstrap搭建网页界面
前端·react.js·bootstrap
鬼火儿8 小时前
15.<Spring Boot 日志>
java·后端
Mos_x8 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
不一样的少年_8 小时前
上班摸鱼看掘金,老板突然出现在身后...
前端·javascript·浏览器
qianbailiulimeng8 小时前
【Spring Boot】Spring Boot解决循环依赖
java·后端
何中应8 小时前
Spring Boot解决循环依赖的几种办法
java·spring boot·后端
江湖人称小鱼哥8 小时前
Redisson 与 Spring Boot 3.4 整合指南
spring boot·redis·后端·redission