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

相关推荐
layman05286 分钟前
webpack5 css-loader:从基础到原理
前端·css·webpack
半桔8 分钟前
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典
前端·css·html
AI老李8 分钟前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·postcss
_OP_CHEN10 分钟前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化
啊哈一半醒12 分钟前
CSS 主流布局
前端·css·css布局·标准流 浮动 定位·flex grid 响应式布局
PHP武器库14 分钟前
ULUI:不止于按钮和菜单,一个专注于“业务组件”的纯 CSS 框架
前端·css
电商API_1800790524723 分钟前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫
晓晓莺歌24 分钟前
vue3某一个路由切换,导致所有路由页面均变成空白页
前端·vue.js
一点程序37 分钟前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
Up九五小庞1 小时前
开源埋点分析平台 ClkLog 本地部署 + Web JS 埋点测试实战--九五小庞
前端·javascript·开源