Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions SimpleBudgetTracker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Simple Budget Tracker

一个适合初学者的 Java 命令行记账小项目,演示类、枚举、集合、文件读写和命令行交互等基础知识。

## 功能
- 添加收入或支出记录。
- 查看全部记录。
- 查看统计信息(总收入、总支出、净资产)。
- 将记录保存到本地文件并在程序启动时自动加载。

## 项目结构
```
SimpleBudgetTracker/
├── README.md
├── data/
│ └── transactions.txt
└── src/
└── com/example/budget/
├── TransactionType.java
├── Transaction.java
├── BudgetManager.java
├── StorageUtil.java
└── Main.java
```

## 运行步骤
1. 安装 JDK 11 或更高版本,并确保 `java` 与 `javac` 可在终端运行。
2. 在项目根目录执行以下命令编译:
```bash
javac -d out src/com/example/budget/*.java
```
3. 运行程序:
```bash
java -cp out com.example.budget.Main
```
4. 根据命令行提示进行操作。程序会自动读取和保存 `data/transactions.txt` 文件。

## VS Code 运行提示
- 安装 Extension Pack for Java。
- 打开 `Main.java` 并点击右上角的 “Run” 图标即可运行。
- 或者在 VS Code 终端中执行上述命令。

祝学习愉快!
Empty file.
46 changes: 46 additions & 0 deletions SimpleBudgetTracker/src/com/example/budget/BudgetManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.example.budget;

import java.util.ArrayList;
import java.util.List;

public class BudgetManager {
private final List<Transaction> transactions;

public BudgetManager() {
this.transactions = new ArrayList<>();
}

public void addTransaction(Transaction transaction) {
transactions.add(transaction);
}

public List<Transaction> getAllTransactions() {
return transactions;
}

public double getTotalIncome() {
return transactions.stream()
.filter(t -> t.getType() == TransactionType.INCOME)
.mapToDouble(Transaction::getAmount)
.sum();
}

public double getTotalExpense() {
return transactions.stream()
.filter(t -> t.getType() == TransactionType.EXPENSE)
.mapToDouble(Transaction::getAmount)
.sum();
}

public double getNetBalance() {
return getTotalIncome() - getTotalExpense();
}

public void printSummary() {
System.out.println("========== Summary ==========");
System.out.printf("Total Income : %.2f%n", getTotalIncome());
System.out.printf("Total Expense: %.2f%n", getTotalExpense());
System.out.printf("Net Balance : %.2f%n", getNetBalance());
System.out.println("=============================");
}
}
95 changes: 95 additions & 0 deletions SimpleBudgetTracker/src/com/example/budget/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.example.budget;

import java.util.Scanner;

public class Main {
private static final String DATA_FILE = "data/transactions.txt";

public static void main(String[] args) {
BudgetManager manager = new BudgetManager();
StorageUtil.loadTransactions(manager, DATA_FILE);

Scanner scanner = new Scanner(System.in);
boolean running = true;

while (running) {
printMenu();
System.out.print("请选择操作:");
String choice = scanner.nextLine().trim();

switch (choice) {
case "1":
addTransaction(manager, scanner, TransactionType.INCOME);
break;
case "2":
addTransaction(manager, scanner, TransactionType.EXPENSE);
break;
case "3":
printTransactions(manager);
break;
case "4":
manager.printSummary();
break;
case "5":
StorageUtil.saveTransactions(manager.getAllTransactions(), DATA_FILE);
break;
case "0":
running = false;
StorageUtil.saveTransactions(manager.getAllTransactions(), DATA_FILE);
break;
default:
System.out.println("无效选择,请重新输入。");
}
}

scanner.close();
System.out.println("谢谢使用记账系统,已退出。");
}

private static void printMenu() {
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.println("=======================");
}

private static void addTransaction(BudgetManager manager, Scanner scanner, TransactionType type) {
System.out.print("请输入金额:");
String amountInput = scanner.nextLine().trim();
double amount;
try {
amount = Double.parseDouble(amountInput);
} catch (NumberFormatException e) {
System.out.println("金额格式不正确,请重新输入。");
return;
}

if (amount <= 0) {
System.out.println("金额必须大于0。");
return;
}

System.out.print("请输入描述:");
String description = scanner.nextLine().trim();
if (description.isEmpty()) {
description = type == TransactionType.INCOME ? "收入" : "支出";
}

Transaction transaction = new Transaction(amount, type, description);
manager.addTransaction(transaction);
System.out.println("成功添加记录:" + transaction.format());
}

private static void printTransactions(BudgetManager manager) {
System.out.println("\n===== 当前记录 =====");
if (manager.getAllTransactions().isEmpty()) {
System.out.println("暂无记录。");
} else {
manager.getAllTransactions().forEach(t -> System.out.println(t.format()));
}
}
}
44 changes: 44 additions & 0 deletions SimpleBudgetTracker/src/com/example/budget/StorageUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.example.budget;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class StorageUtil {
public static void saveTransactions(List<Transaction> transactions, String filePath) {
try (BufferedWriter writer = Files.newBufferedWriter(Path.of(filePath))) {
for (Transaction t : transactions) {
writer.write(t.toFileFormat());
writer.newLine();
}
System.out.println("记录已成功保存到 " + filePath);
} catch (IOException e) {
System.err.println("保存记录失败: " + e.getMessage());
}
}

public static void loadTransactions(BudgetManager manager, String filePath) {
Path path = Path.of(filePath);
if (!Files.exists(path)) {
System.out.println("未找到交易记录文件,将创建新文件。");
return;
}
try (BufferedReader reader = Files.newBufferedReader(path)) {
String line;
while ((line = reader.readLine()) != null) {
try {
Transaction transaction = Transaction.fromFileFormat(line);
manager.addTransaction(transaction);
} catch (IllegalArgumentException ex) {
System.err.println("跳过无效记录: " + line);
}
}
System.out.println("已从文件加载记录。");
} catch (IOException e) {
System.err.println("加载记录失败: " + e.getMessage());
}
}
}
65 changes: 65 additions & 0 deletions SimpleBudgetTracker/src/com/example/budget/Transaction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.example.budget;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Transaction {
private final double amount;
private final TransactionType type;
private final String description;
private final LocalDateTime timestamp;

public Transaction(double amount, TransactionType type, String description) {
this.amount = amount;
this.type = type;
this.description = description;
this.timestamp = LocalDateTime.now();
}

public Transaction(double amount, TransactionType type, String description, LocalDateTime timestamp) {
this.amount = amount;
this.type = type;
this.description = description;
this.timestamp = timestamp;
}

public double getAmount() {
return amount;
}

public TransactionType getType() {
return type;
}

public String getDescription() {
return description;
}

public LocalDateTime getTimestamp() {
return timestamp;
}

public String format() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return String.format("%s | %s | %.2f | %s",
formatter.format(timestamp), type, amount, description);
}

public String toFileFormat() {
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
return String.format("%s|%s|%.2f|%s",
formatter.format(timestamp), type, amount, description.replace("|", "/"));
}

public static Transaction fromFileFormat(String line) {
String[] parts = line.split("\\|");
if (parts.length < 4) {
throw new IllegalArgumentException("Invalid line: " + line);
}
LocalDateTime time = LocalDateTime.parse(parts[0]);
TransactionType type = TransactionType.valueOf(parts[1]);
double amount = Double.parseDouble(parts[2]);
String description = parts[3];
return new Transaction(amount, type, description, time);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.example.budget;

public enum TransactionType {
INCOME,
EXPENSE
}