Калькулятор расходов/доходов. Как сделать его проще?
Калькулятор расходов/доходов. Пользователь может ввести расход/доход: описание, сумму.
В файл сохраняются эти поля + дата записи.
В конец файла сохраняется итог по месяцам.
Сделайте базовый класс, и реализации наследников: на базе txt файла,
Как сделать так, чтоб текст продолжал записываться в файл, а не стирал предыдущую или есть другой, более корректный способ выполнить это задание?
Вот моя попытка:
int account = 10000;
char exit = 'n';
boolean isRecord = false;
Scanner scan = new Scanner(System.in);
do {
System.out.println("1. доходы");
System.out.println("2. расходы");
System.out.println("3. Выход");
System.out.print("Пожалуйста, выберите 1-3:");
int choose = scan.nextInt();
do {
if (choose >= 1 && choose <= 3) {
break;
} else {
System.out.print("Ввод неправильный, и ввод:");
choose = scan.nextInt();
}
} while (true);// Убедитесь, что ввод неверен
switch (choose) {
case 1:
isRecord = true;
System.out.print("Эта сумма дохода:");
int in = scan.nextInt();
account += in;
System.out.print("Описание суммы дохода:");
String input = scan.next();
System.out.println("Дата: ");
String date = scan.next();
writeToFile(String.valueOf(in + input + date));
break;
case 2:
isRecord = true;
System.out.print("Сумма этих расходов:");
int out = scan.nextInt();
account -= out;
System.out.print("Описание расходов:");
String output = scan.next();
System.out.println(account);
break;
case 3:
System.out.println("Подтвердите выход? Y/N");
String str = scan.next();
exit = str.charAt(0);
break;
}
if (exit == 'y') {
break;
}
} while (true);
//
public static void writeToFile(String str) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter("k.txt"));
writer.write(str);
writer.close();
}
Ответы (2 шт):
Есть такой вариант для решения вашей задачи:
private static void writeToFile(String str) throws IOException {
List<String> lines = new ArrayList<>();
lines.add(str);
Files.write(Paths.get("k.txt"),
lines,
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
}
Если файла не существует, он будет создан, а если существует - строка будет дописана в его конец. Кодировка - UTF-8. При этом происходит автоматический контроль за открытием-закрытием файлов, поэтому самостоятельно этим заниматься не нужно.
Ну, я попробовала сделать это. Все файлы:
MoneyTransfer.java:
import java.time.LocalDate;
/**
* класс, представляющий собой переход денег
* (расход или доход)
*/
public abstract class MoneyTransfer implements Comparable<MoneyTransfer> {
protected int value;
protected LocalDate date;
protected String description;
public static final String CURRENCY = "$";
public LocalDate getDate() {
return date;
}
public MoneyTransfer(int value, LocalDate date, String description) {
this.value = value;
this.date = date;
this.description = description;
}
/**
* получить прибавление этого перехода денег к итоговой сумме,
* то есть для расхода это будет value со знаком -,
* а для дохода - value со знаком +
*/
public abstract int getAdditionToSum();
@Override
public String toString() {
return "Сумма: " + value + CURRENCY + " | Дата: " + date + " | Описание: " + description;
}
/**
* сравнение объектов MoneyTransfer по их дате -
* это нужно для сортировки
*/
public int compareTo(MoneyTransfer other) {
return date.compareTo(other.date);
}
}
Revenue.java:
import java.time.LocalDate;
/**
* класс, представляющий собой доход денежных средств
*/
public class Revenue extends MoneyTransfer {
public Revenue(int value, LocalDate date, String description) {
super(value, date, description);
}
@Override
public int getAdditionToSum() {
return value;
}
@Override
public String toString() {
return " * Доход * \n" + super.toString();
}
}
Expense.java:
import java.time.LocalDate;
/**
* класс, представляющий собой расход денежных средств
*/
public class Expense extends MoneyTransfer {
public Expense(int value, LocalDate date, String description) {
super(value, date, description);
}
@Override
public int getAdditionToSum() {
return -value;
}
@Override
public String toString() {
return " * Расход * \n" + super.toString();
}
}
Account.java:
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDate;
import java.util.*;
/**
* класс, представляющий собой счёт с денежными средствами
*/
public class Account {
private List<MoneyTransfer> moneyTransfers = new ArrayList<>();
private final String FILENAME = "account.txt";
private final int INITIAL_VALUE;
public Account(int initialValue) {
this.INITIAL_VALUE = initialValue;
}
/**
* рассчитать текущий баланс
*/
public int calculateCurrentBalance() {
int balance = INITIAL_VALUE;
for (MoneyTransfer transfer : moneyTransfers) {
balance += transfer.getAdditionToSum();
}
return balance;
}
/**
* добавить денежный переход (расход или доход) в список
*/
public void addMoneyTransfer(MoneyTransfer transfer) {
moneyTransfers.add(transfer);
}
/**
* записать информацию в файл
*/
public void saveToFile() throws IOException {
Collections.sort(moneyTransfers);
String result = getAllMoneyTransfersString() + "\n\n" + getAllMonthsResultsString();
writeToFile(result);
}
/**
* получить строку со всеми доходами и расходами
*/
private String getAllMoneyTransfersString() {
StringBuilder sb = new StringBuilder("---------КАЛЬКУЛЯТОР ДОХОДОВ И РАСХОДОВ---------");
for (MoneyTransfer transfer : moneyTransfers) {
sb.append("\n").append(transfer.toString());
}
return sb.toString();
}
/**
* получить строку с результатами по месяцам
*/
private String getAllMonthsResultsString() {
if (moneyTransfers.size() == 0) {
return "";
}
StringBuilder sb = new StringBuilder("----РЕЗУЛЬТАТЫ ПО МЕСЯЦАМ----");
int lastMonth = moneyTransfers.get(0).getDate().getMonthValue();
int lastYear = moneyTransfers.get(0).getDate().getYear();
int transferResultForMonth = moneyTransfers.get(0).getAdditionToSum();
for (int i = 1; i < moneyTransfers.size(); i++) {
MoneyTransfer transfer = moneyTransfers.get(i);
if (!doesDateMatchMonthAndYear(transfer.getDate(), lastMonth, lastYear)) {
String monthResultStr = createStringResultForMonthOfYear(transferResultForMonth, lastMonth, lastYear);
sb.append("\n").append(monthResultStr);
transferResultForMonth = 0;
}
lastMonth = transfer.getDate().getMonth().getValue();
lastYear = transfer.getDate().getYear();
transferResultForMonth += transfer.getAdditionToSum();
}
String monthResultStr = createStringResultForMonthOfYear(transferResultForMonth, lastMonth, lastYear);
sb.append("\n").append(monthResultStr);
return sb.toString();
}
/**
* сформировать строку для записи результата по месяцу года
*/
private String createStringResultForMonthOfYear(int transferResult, int month, int year) {
StringBuilder sb = new StringBuilder();
sb.append("За ").append(month).append(" месяц ");
sb.append(year).append(" года : ");
sb.append(transferResult).append(MoneyTransfer.CURRENCY);
return sb.toString();
}
/**
* проверка, подходит ли дата под месяц и год
*/
private boolean doesDateMatchMonthAndYear(LocalDate date, int month, int year) {
return date.getMonthValue() == month && date.getYear() == year;
}
/**
* запись строки в файл: пересоздать файл для записи
*/
private void writeToFile(String str) throws IOException {
List<String> lines = Arrays.asList(str.split("\n"));
Files.write(Paths.get(FILENAME),
lines,
StandardCharsets.UTF_8,
StandardOpenOption.CREATE);
}
}
Main.java:
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.Scanner;
public class Main {
private static final Scanner scanner = new Scanner(System.in);
private static Account account;
public static void main(String[] args) {
final int INITIAL_VALUE = 10000;
account = new Account(INITIAL_VALUE);
boolean continuing = true;
while (continuing) {
printMenu();
int choice = askUserForInputUntilItIsCorrect();
try {
continuing = handleMenuChoiceAndReturnContinuing(choice);
} catch (IncorrectInputException ex) {
System.out.println(ex.getMessage());
} catch (IOException ex) {
System.out.println("Ошибка при работе с файлами: " + ex.getMessage());
}
printAccountBalance();
}
}
/**
* обработать ввод пункта меню
* и вернуть true - если нужно продолжать,
* false - если пора выйти из программы
*/
private static boolean handleMenuChoiceAndReturnContinuing(int choice) throws IncorrectInputException, IOException {
switch (choice) {
case 1:
handleRevenue();
break;
case 2:
handleExpense();
break;
case 3:
if (doesUserReallyWantsToExit()) {
return false;
}
break;
}
return true;
}
/**
* вывести баланс в консоль
*/
private static void printAccountBalance() {
System.out.println("Текущий баланс: " + account.calculateCurrentBalance() + MoneyTransfer.CURRENCY);
}
/**
* обработать ввод и сохранение дохода
*/
private static void handleRevenue() throws IncorrectInputException, IOException {
System.out.print("Введите сумму дохода -> ");
int revenueValue = getIntFromInputOrThrown();
System.out.print("Введите описание дохода -> ");
String description = scanner.nextLine();
System.out.print("Дата (формат ГГГГ-ММ-ДД) -> ");
LocalDate date = getDateFromInputOrThrown();
Revenue revenue = new Revenue(revenueValue, date, description);
account.addMoneyTransfer(revenue);
account.saveToFile();
}
/**
* обработать ввод и сохранение расхода
*/
private static void handleExpense() throws IOException, IncorrectInputException {
System.out.print("Введите сумму расхода -> ");
int expenseValue = getIntFromInputOrThrown();
System.out.print("Введите описание расхода -> ");
String description = scanner.nextLine();
System.out.print("Дата (формат ГГГГ-ММ-ДД) -> ");
LocalDate date = getDateFromInputOrThrown();
Expense expense = new Expense(expenseValue, date, description);
account.addMoneyTransfer(expense);
account.saveToFile();
}
/**
* подвердить выход
*/
private static boolean doesUserReallyWantsToExit() {
System.out.println("Подтвердите выход? y/n");
char answer = scanner.nextLine().charAt(0);
final char EXIT_YES = 'y';
return answer == EXIT_YES;
}
/**
* спрашивать ввод у пользователя до тех пор,
* пока он не напишет корректный пункт меню
*/
private static int askUserForInputUntilItIsCorrect() {
do {
try {
int number = getIntFromInputOrThrown();
checkIsCorrectMenuOption(number);
return number;
} catch (IncorrectInputException ex) {
System.out.println(ex.getMessage());
System.out.print("Попробуйте ввести пункт меню ещё раз -> ");
}
} while (true);
}
/**
* конвертация ввода пользователя в опцию меню,
* может выбросить исключение, если ввод некорректный
*/
private static void checkIsCorrectMenuOption(int number) throws IncorrectInputException {
if (number < 1 || number > 3) {
throw new IncorrectInputException("Нужно ввести число от 1 до 3");
}
}
/**
* получить число из ввода,
* если некорректный ввод - выбросить исключение
*/
private static int getIntFromInputOrThrown() throws IncorrectInputException {
String input = scanner.nextLine();
try {
return Integer.parseInt(input);
} catch (NumberFormatException ex) {
throw new IncorrectInputException("Нужно ввести целое число");
}
}
/**
* получить дату из ввода,
* если некорректный ввод - выбросить исключение
*/
private static LocalDate getDateFromInputOrThrown() throws IncorrectInputException {
String input = scanner.nextLine();
try {
return LocalDate.parse(input);
} catch (DateTimeParseException ex) {
throw new IncorrectInputException("Нужно ввести корректный формат даты");
}
}
/**
* вывод меню в консоль
*/
private static void printMenu() {
System.out.println("1. Доходы");
System.out.println("2. Расходы");
System.out.println("3. Выход");
System.out.print("Пожалуйста, выберите пункт меню (1-3) -> ");
}
}
IncorrectInputException.java:
/**
* исключение для случая,
* когда пользователь неправильно вводит информацию
*/
public class IncorrectInputException extends Exception {
public IncorrectInputException(String message) {
super(message);
}
}

