目录
需求说明
该软件能够记录家庭的收入、支出,并能够打印收支明细表。
项目采用分级菜单方式。主菜单如下:
-----------------家庭收支记账软件-----------------
1 收支明细
2 登记收入
3 登记支出
4 退 出 请选择(1-4):_
1. 假设家庭起始的生活基本金为10000元。
2. 查询收支明细(菜单1)时,将显示所有的收入、支出名细列表。
3. 每次登记收入(菜单2)后,收入的金额应累加到基本金上,并记录本次收入明细,以便后续的查询。
4. 每次登记支出(菜单3)后,支出的金额应从基本金中扣除,并记录本次支出明细,以便后续的查询。
5. 点击退出(菜单4)后,确认该操作后即可退出程序。
软件设计
界面展示
设计思路:
(怎样来保存数据?) 我们要保存一组多维度的数据使用一维数组难以做到,此时应该使用二维数组进行数据存取。
(界面效果要怎样设计?) 经过观察发现当我们选择退出后程序才会结束运行,所以界面的展示应该写在一个死循环里面。
(怎样选择要执行的操作?) 根据我们所学的基础知识,不难发现使用switch语句就可以做到。
为了简化主界面代码,我把对应实现的功能设计成各个方法,使用时直接调用即可。(设计的各个方法写在本类中,主方法main之外)
界面效果的代码:
//导包
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Demo {
//定义私有静态对象,创建后每个方法都可使用
private static Scanner sc = new Scanner(System.in);
//定义账户余额,并设置初始值
private static int sumMoney = 10000;
//定义数组中记录的条数
private static int count = 0;
public static void main(String[] args) {
//定义二维数组并设置容量
String[][] arr = new String[10][4];
//定义一个boolean值,用于判断主界面的循环
boolean flag=true;
while(flag){
//调用数组扩容的方法
arr = expandArray(arr);
System.out.println("\n----------------家庭收支记账软件----------------\n");
System.out.println(" 1.收支明细");
System.out.println(" 2.登记收入");
System.out.println(" 3.登记支出");
System.out.println(" 4.退 出\n");
System.out.print("请选择(1-4): ");
//输入你想要进行的操作数
String num = sc.next();
//调用判断输入的方法
char b1 = readMenuSelection(num);
switch(b1){
case '1':
//调用查看信息的方法
readInfo(arr);
break;
case '2':
//调用添加收入记录的方法
addRecord(arr);
break;
case '3':
//调用添加支出记录的方法
reduceRecord(arr);
break;
case '4':
//调用选择退出的方法
boolean b = quitSystem();
if(b==true)
flag=false;
else break;
}
}
}
}
界面效果图:
设计判断输入的各个方法
1. 判断主界面功能选择输入的方法
目的:用户输入错误时给出提示,直到输入正确的操作数字符后再进行操作,而不是输入错误,程序就直接停止运行。
//创建判断输入的方法
//返回值类型char(需要返回一个字符和操作数字符匹配)
//参数为String(用户输入的类型是String)
public static char readMenuSelection(String n) {
char c;
//设置死循环,满足条件后退出,直到获取到正确操作数字符
while(true){
//获取参数字符串的第一个字符
c = n.charAt(0);
//判断是否对应给定的操作数字符
if (c != '1' && c != '2' && c != '3' && c != '4') {
System.out.print("输入数字错误,请按提示正确输入:");
String n1 = sc.next();
n = n1;
} else break;
}
//返回给定的正确操作数字符
return c;
}
2. 判断输入是否全为数字
目的: 在用户输入收入金额和支出金额时进行判断,为了使输入的内容规范,要求输入的字符串只能是数字,然后再转换成 int 类型的数字进行操作。
//把全为数字的字符串转换为int类型,并返回其数值
public static int printInt(String x){
//调用判断字符串是否全为数字的方法的返回值进行判断
if(isNumberic(x)){
//将获取到的数字字符串转为int类型的数字
int y = Integer.parseInt(x);
return y;
}else{
//写一个死循环,直到用户输入全为数字字符串时才停止
while(true){
System.out.print("你输入的值无意义! 请你重新输入: ");
String num = sc.next();
if(isNumberic(num)){
int y1 = Integer.parseInt(num);
return y1;
}
}
}
}
//判断字符串是否全是数字,是返回true,否则返回false
//设置参数为String类型的字符串
public static boolean isNumberic(String str) {
//使用正则表达式进行判断是否全为数字
Pattern pattern = Pattern.compile("[0-9]*");
return pattern.matcher(str).matches();
}
3. 判断输入是否全为汉字
目的:在用户输入收入说明和支出说明时进行判断,为了使输入的内容规范,要求输入的字符串只能是汉字。
//判断字符串是否全为汉字,是则返回,否则从新输入字符串
public static String printString(String x){
if(isChinese(x)){
return x;
}else{
while(true){
System.out.print("输入错误! 请你重新输入: ");
String t = sc.next();
if(isChinese(t)){
return t;
}
}
}
}
//判断字符串是否全是汉字,是返回true,否则返回false
public static boolean isChinese(String str) {
//使用正则表达式进行判断是否全为汉字
Pattern p_str = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher m = p_str.matcher(str);
if(m.find()&&m.group(0).equals(str)){
return true;
}
return false;
}
添加收入记录的方法
设计思路:根据需求可知用户首先应该输入收入的金额及说明,并且判断输入的规范性;然后再算出增加收入后的总金额;最后将各个记录保存到二维数组中。(将数组中的记录条数加1)
代码实现:
//创建添加收入记录的方法
//该方法直接使用无需返回值,设置参数为String类型的二维数组
public static void addRecord(String[][] arr){
System.out.println("收入的金额:");
String num1 = sc.next();
//调用判断输入是否全为数字的方法
int money = printInt(num1);
System.out.println("收入的原因:");
String b1 = sc.next();
//调用判断输入是否全为汉字的方法
String because = printString(b1);
arr[count][0]="收入";
//计算收入的总金额值
sumMoney += money;
//将int类型的总金额和收入金额转为String类型
String t1=String.valueOf(sumMoney);
String t2=String.valueOf(money);
arr[count][1]=t1;
arr[count][2]=t2;
arr[count][3]=because;
//数组中的记录条数加1
count++;
System.out.println("添加成功!");
}
效果展示:
添加支出记录的方法
设计思路:跟添加收入记录的方法大同小异,可对比起来设计。(将数组中的记录条数加1)
代码实现:
//创建添加支出记录的方法
public static void reduceRecord(String[][] arr){
System.out.println("支出的金额:");
String num2 = sc.next();
int money1 = printInt(num2);
System.out.println("支出的原因:");
String b2 = sc.next();
String because1 = printString(b2);
arr[count][0]="支出";
sumMoney -= money1;
String t3=sumMoney+"";
String t4=money1+"";
arr[count][1]=t3;
arr[count][2]=t4;
arr[count][3]=because1;
count++;
System.out.println("添加成功!");
}
效果展示:
查看信息记录的方法
设计思路:用户在还没有录入信息的时候也有可能会进行查询操作,此时我们首先就应该进行判断并给出提示信息;然后再进行二维数组的遍历;最后进行判断查询的类别,格式化输出记录。
代码实现:
//创建查看信息的方法
public static void readInfo(String[][] arr){
//判断二维数组是否为空,如果为空给出提示信息,如不为空进行查询操作
if(arr[0][0]==null){
System.out.println("暂无收支记录,账户余额为:10000元");
}else{
System.out.println("收支\t\t账户总金额\t\t收支金额\t\t说 明");
//循环二维数组
for(int i=0; i<arr.length; i++){
//循环二维数组中的一维数组
for(int j=0; j<arr[i].length; j++){
if(arr[i][j]!=null){
//判断查询的记录是收入还是支出,以便给出不同的展示效果
if(arr[i][0]=="收入"){
//格式化输出,为了美观
System.out.println(String.format("%-6s %-15s +%-11s %-8s",arr[i][j],arr[i][1],arr[i][2],arr[i][3]));
break;
}else{
System.out.println(String.format("%-6s %-15s -%-11s %-8s",arr[i][j],arr[i][1],arr[i][2],arr[i][3]));
break;
}
}
}
}
}
}
效果展示:
确认退出的方法
设计思路:给出提示语句让用户输入,再对用户的输入进行判断,如果输入的是y或者Y表示用户确认退出返回 true,输入其他则认为用户选择取消退出返回 false。
代码实现:
//创建选择退出的方法
//返回值设置为boolean类型,无参数传递
public static boolean quitSystem(){
System.out.print("确定退出?(输入y确认操作): ");
//单个字符不能直接输入,此时我们输入一个字符串
String t = sc.next();
//获取字符串的第一个字符
char tc = t.charAt(0);
//获取该字符的ASCII码
int tc1 = (int)tc;
//y的ASCII码121,Y的ASCII码89
//判断用户输入的字符串是否是一个字符并且为y或则Y,满足条件则返回true,否则返回false
if((tc1==121 && t.length()==1) || (tc1==89 && t.length()==1)){
System.out.println("\n退出成功!");
return true;
}else{
System.out.println("\n已取消退出");
return false;
}
}
效果展示:
二维数组扩容的方法
设计目的:二维数组的容量是固定的,可以看出本次二维数组的最大存储数据条数为10,当我们录入的记录条数超过这个限制时,程序就会报错并且结束运行,给用户不好的体验,因此,对于给二维数组的扩容就很有必要。
设计思路:定义一个扩容后的新二维数组,再判断原二维数组中的数据条数达到最大值时,如果达到了最大值,就把原二维数组中的数据传入到新二维数组,最后返回新二维数组;如果没有达到最大值时,最后返回原二维数组。
代码实现:
//二维数组扩容
//设置返回值为二维数组,参数也为二维数组
public static String[][] expandArray(String[][] arr){
//定义一个在原二维数组基础上扩容的二维数组
String[][] arr1 = new String[arr.length+10][4];
//判断传入的二维数组的数据条数是否已经达到最大容量
if(arr[arr.length-1][0] != null){
//使用循环把传入的二维数组中的数据赋值给扩容后的新二维数组
for(int i=0; i<arr.length; i++){
for(int j=0; j<4; j++){
arr1[i][j] = arr[i][j];
}
}
//返回扩容后的新二维数组
return arr1;
}else {
//返回原二维数组
return arr;
}
}
总结
该程序总的来说还是比较简单,非常适合作为 Java 初学者的练习小项目,这也是小编初学 Java 以来做的第一个小项目;在编写代码的时候还是需要注意部分的细节 (比如:添加记录后的二维数组记录条数要增加 1、int 类型数据转为 String 类型、单个字符不能直接输入,应该输入字符串后获取单个字符...);以上代码完全可以正常运行,希望对正在学习 Java 的你有许些帮助,如有任何问题,请联系小编~