前言
经过一段时间的基础学习,做一个简单的家庭记账程序。
要求
代码及记录
主界面
注:有参考
为了方便使用Scanner,声明为私有静态对象,这个类的所有方法都可以使用,还有起始的基本金和程序的收支进账的记录。这里使用二维数组对收支记录进行存储数据,注意输入的数据类型。用户在使用程序时,主界面除非退出都会在操作完毕后显示,因此用一个死循环在主界面。输入的数字为string类型。switch语句对输入的数字进行判断,然后调用相应的方法。
public class Utility {
//私有静态对象,每个方法都可使用
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];//只有10条记录
boolean flag=true;
while(flag){
//扩容
String[][] arr1 = expandArray(arr);//创建一个新的数组进行接收
arr = arr1;//进行数组替换
System.out.println("-----------------家庭收支记账软件-----------------");
System.out.println();
System.out.println(" 1 收支明细");
System.out.println(" 2 登记收入");
System.out.println(" 3 登记支出");
System.out.println(" 4 退 出");
System.out.println();
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;}
}
}
}
判断菜单输入的选择是否合法
要对菜单选择进行判断,这里声明一个char类型的变量c,获取字符串的第一个字符,n.charAt()括号里是索引,标明字符串的第几个字符。如果没有按照1-4输入,就提示重新输入,声明一个新变量接收数据,将其赋值给变量n,接着判断,直到输入正确为止,最终返回c。
public static char readMenuSelection(String n){
char c;
//创建死循环
while(true){
c=n.charAt(0);//获取字符串第一个字符
//判断是否按照1-4输入
if(c != '1' && c != '2' && c != '3' && c != '4' ){
System.out.println("输入数字错误,请按照提示正确输入:");
String n1 = sc.next();
n = n1;//新输入赋值给n,直到符合提示退出循环
}else break;
}
return c;
}
查看收支明细
首先要有收入支出的记录,也就是要判断二维数组是否为空,为空给出提示,不为空就进行查询操作。二维数组遍历需要两个for循环,查询第一列中为"收入"和"支出"的数据,并且格式化输出,运用到String.format。
//查看收支明细
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;
}
}
}
}
}
}
判断输入的金额和原因是否合法
定义四个方法,首先是boolean isNumberic正则式判断是否全为数字,用pattern和matcher类实现,其次是 int printInt将字符串数字转换为数字类型Integer.parseInt(x),返回数值,然后是正则式判断是否全为汉字 boolean isChinese,最后是printString。
//判断字符串是否全是数字
public static boolean isNumberic(String str){
//使用正则式判断是否全为数字
Pattern pattern = Pattern.compile("[0-9]*");
return pattern.matcher(str).matches();
}
//将字符串转换为int类型,返回数值
public static int printInt(String x){
if(isNumberic(x)){//是否全是数字
//将数字字符串转为int型数字
int y = Integer.parseInt(x);
return y;
}else{
while(true){//死循环,直到输入正确为止
System.out.println("输入出错,请重新输入:");
String num=sc.next();
if(isNumberic(num)){
int y1 = Integer.parseInt(num);
return y1;
}
}
}
}
//判断是否全是汉字,是返回true,不是返回false
public static boolean isChinese(String str){
//正则表达式判断是否全为汉字
Pattern p_str = Pattern.compile("[\\u4e00-\\u9fa5]+");
Matcher m =p_str.matcher(str);//matcher类提供分组支持
if(m.find()&&m.group(0).equals(str)){//find任意位置字符串匹配,group返回字符串索引匹配的字符串
return true;
}
return false;
}
//判断是否全是汉字,是就返回,否则重新输入字符串
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;
}
}
}
}
收入和支出
注意,每次登记收入和支出都要记录count+1。
将int型的数据转为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;
count++;//总的收支记录加一
System.out.println("添加成功!");
}
//登记支出,同样不用返回
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("添加成功!");
}
退出系统
判断确定退出的输入确认,y或者Y,对照的ascii码。
public static boolean quitSystem(){
System.out.println("确定退出?输入[Y/N]确认:");
String t=sc.next();
char tc=t.charAt(0);
int tc1=(int)tc;//强制转换ASC码y的ASCII码121,Y的ASCII码89
if((tc1==121 && t.length()==1) || (tc1==89 && t.length()==1)){
System.out.println("\n退出成功!");
return true;
}else {
System.out.println("\n已取消退出!");
return false;
}
}
数组扩容
在系统运行中发现,二维数组的长度是有限,那么为了解决这个问题,可以用数组扩容,将原本数组的数据赋值到新的数组中。
//二维数组扩容,参数为二维数组
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<arr[0].length;j++){//注意二维数组的行数
arr1[i][j] = arr[i][j];
}
}
return arr1;
}else{
return arr;
}
}
在程序运行中,遇到了问题,使用debug查看,注意二维数组的遍历,因为这里是10行4列,行数和列数并不相等,列数变量j的遍历就要是arr[0].length,表示第0行的列数。
//扩容
String[][] arr1 = expandArray(arr);//创建一个新的数组进行接收
arr = arr1;//进行数组替换
注意,在数组扩容方法调用时,需要创建一个新的数组去接收,然后进行数组替换,如果直接调用expandArray(arr),新创建的数组没有被接收,会出现报错。
总结
二维数组的使用,在遍历当中需要注意行数和列数,在记账程序中,会受到数组长度的限制,无法存储更多的记录,就可以用数组扩容的方法。