在征得陈老师的同意下,使用java面向对象语言+IDEA工具完成本次作业
虽然说VS是宇宙最好的集成开发编程软件,但是咱们的IDEA也不是等闲之辈,她的美丽唯有心人耐心发现,方能觉察此番美景。
话不多说,咱么直接一探究竟。
首先官网下载好IDEA,以及Git。
以及准备好自己github的项目(我已经在助教的github上fork到自己的账号了)
打开IDEA。
请注意,咱们现在需要去配置Git->然后克隆项目到本地。
IDEA面板中->File->Setting->Version Control -> Git->如图配置
现在咱们已经配置了git,那么现在就开始clone一个项目到本地,进行开发
File->Project from version Control... -> Git
输入你想要克隆的项目URL->点击Clone即可等待完成
克隆完成后,在当前文件夹下创建一个module项目,即可开始在ertron/src文件夹下编写代码:
在完成了上述配置任务过后,即可开始愉悦地编码了。
咱们先来看看题目:
阿超家里的孩子上小学一年级了,这个暑假老师给家长们布置了一个作业:家长每天要给孩子出一些合理的,但要有些难度的四则运算题目,并且家长要对孩子的作业打分记录。
作为程序员的阿超心想,既然每天都需要出题,那何不做一个可以自动生成小学四则运算题目与解决题目的命令行 “软件”呢。他把老师的话翻译一下,就形成了这个软件的需求:
程序接收一个命令行参数 n,然后随机产生 n 道加减乘除(分别使用符号+-*/来表示)练习题,每个数字在 0 和 100 之间,运算符在 2 个 到 3 个之间。由于阿超的孩子才上一年级,并不知道分数。所以软件所出的练习题在运算过程中不得出现非整数,比如不能出现 3÷5+2=2.6 这样的算式。练习题生成好后,将生成的 n 道练习题及其对应的正确答案输出到一个文件 subject.txt 中。当程序接收的参数为4时,以下为一个输出文件示例。13+17-1=29 11*15-5=160 3+10+4-16=1 15÷5+3-2=4
我的思路:
既然是随机生成式子,再利用题目的一些规则(不能有分数,运算符在2个到3个之间,数字在0和100之间),可以借鉴后续表达式以及简化版的逆波兰算法(利用两个栈分别存储数字,和运算符,进行及时计算)。
编写代码:
创建了两个类CalculatorMachine和CantCalculateException
类CalculatorMachine:计算机机器类,提供一些方法产生符合题目的式子CantCalculateException:自定义异常类,如果遇到不符合题目的计算(出现了分数,或者除以0),则抛出自定义的这个异常,进行重新生成式子,直到符合题意CalculatorMachine.java中的私有属性,详情作用请看注释:
/** * 用于存储生成的题目,使用Set集合数据结构使得题目不会产生重复 */ private HashSet<String> problem = new HashSet<>(); /** * 用于存储数字的栈 */ private Stack<Integer> numbers = new Stack<>(); /** * 用于存储符号的栈 */ private Stack<Integer> operators = new Stack<>(); /** * 用与生成随机数 * random.nextInt(20) :即可得到20以内不包含20的随机数 */ private Random random = new Random();public void getAll()方法:调用其他方法
/** * 传入num题目数目 * 即可将题目写入到subject.txt文件中 * @param num 代表需要的题目数量 * @return 没有任何问题,即返回true代表生成成功 */ public void getAll(int num){ // 循环得到式子直到满足数目 while(problem.size() < num) { getOne(); } if(writeToFile()) { System.out.println("已经根据你的要求生成" + num + "个式子!"); } }public void getOne()方法:生成一个符合要求的算式并且后续表达式得到结果
/** * 用于生成一个符合要求的算式 * 使用后续表达式得到结果 */ public void getOne() { // 用来保存生成的当前式子 String result = ""; // 运算符的个数为 2 或者 3 个 int operator_count = random.nextInt(2)+2; //数字的个数,根据题意,两个符号,则代表3个计算数,三个符号,则代表4个计算数 int num_count = operator_count == 2 ? 3: 4; // 根据后续表达式就搞定了两个栈的东西 61+47*96=4573 for(int i = 0; i < operator_count + num_count ; i++) { // 如果是偶数,则代表着数数字 if(i%2==0) { // 在数字栈中存入一个范围内的随机数 numbers.push(random.nextInt(101)); // 进行符号保存 result += numbers.peek(); // 如果是奇数,则代表着符号位 } else if(i%2!=0) { // 1:+ , 2:- , 3:* 4:/ int opertor = random.nextInt(4) + 1; // 如果遇到+ - 准备入栈顶为 * /的话,需要进行计算 while(!operators.empty() && opertor <=2 && operators.peek() >=3) { result = calculateUtil(result); } // 这个符号符合当前栈的规则,则入栈 operators.push(opertor); // 记录这个符号 if(operators.peek()==1) { result += '+'; } else if(operators.peek() == 2){ result += '-'; } else if(operators.peek() == 3){ result += '*'; } else if(operators.peek() == 4){ result += '÷'; } } } // 根据剩余的栈计算最后的值 while(!operators.empty()) { result = calculateUtil(result); } // 如果最后的计算结果为负数,直接返回,放弃此次的式子 if(numbers.peek()<0){ return; } // 最后加上等于符号 result += '='; // 走到这一步,说明这个式子没有问题,符合题意 // 所以放入到set集合中 problem.add(result+=numbers.pop()); }private int calculator(int a, int b, int operator):根据符号计算
/** * 根据符号计算 */ private int calculator(int a, int b, int operator) throws ArithmeticException, CantCalculateException { if(operator == 1) { return a+b; } else if(operator == 2) { return a-b; } else if(operator == 3) { return a*b; } else if(operator == 4) { // 如果不能整除,则抛出我们自定义的Exception if(a<b || a%b != 0) { throw new CantCalculateException(); } return a/b; } return 0; }private String calculateUtil(String result)方法:进行后续表达式特殊计算
/** * 进行后续表达式特殊计算 * + - 入栈顶为 * / 的情况 * 除法带有分数的情况 * @param result * @return */ private String calculateUtil(String result){ int a = numbers.pop(); int b = numbers.pop(); try { int this_operator = operators.pop(); if(!operators.isEmpty() && this_operator==2 && operators.peek()==2) { numbers.push(calculator(b,a,1)); }else if (!operators.isEmpty() && this_operator==4 && operators.peek()==4) { numbers.push(calculator(b,a,3)); } else { numbers.push(calculator(b,a,this_operator)); } } catch (CantCalculateException e) { int pr_b = b; a = random.nextInt(101); b = random.nextInt(101); // a除数不能为0,满足b能够整除a,满足b>a while (a == 0 || b % a != 0 || b < a || b > 100) { a = random.nextInt(101); b = random.nextInt(101) + a; } numbers.push(b); numbers.push(a); operators.push(4); result = result.substring(0, result.indexOf(pr_b + "")); result += b; result += '÷'; result += a; } return result; }private boolean writeToFile():将生成的所有式子写入到subject.txt
/** * 将生成的所有式子写入到subject.txt * @return */ private boolean writeToFile() { File file = new File("subject.txt"); try{ if(!file.exists()) { file.createNewFile(); } FileWriter fileWriter = new FileWriter(file.getAbsoluteFile()); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); for(String s : problem) { bufferedWriter.write(s); bufferedWriter.newLine(); } bufferedWriter.close(); } catch (Exception e) { e.printStackTrace(); } return true; }对于java来说有专门的junit单元测试包,非常方便进行单元测试。
第一步:在需要测试类中Ctrl+Alt+T出现单元测试提示框 -> Create New Test...
第二步:在测试类中调用需要测试的类的方法
第三步:运行测试类,查看测试结果,是否成功
测试完成,上述程序符合题目要求且成功运行
单步调试有利于实时看到每一步的代码中变量的值变化。
非常适合用于排错。
JProfiler是用于分析J2EE软件性能瓶颈并能准确定位到Java类或者方法有效解决性能问题的主流工具,它通常需要与性能测试工具如:LoadRunner配合使用,因为往往只有当系统处于压力状态下才能反映出性能问题。
所以我采用JProfiler进行性能测试。
下载安装JProfiler过后需要在IDEA进行配置,首先File->Setting->Plugins搜索下载JProfiler插件
安装完插件过后,配置JProfiler的启动程序的地址。
配置完毕即可点击左边的JProfiler启动检测
首先Commit提交修改的代码到本地仓库
Commit过后push到自己的github账号上面
登录自己的github账号去检查是否push成功
提交到源库
其实在之前就用过git进行push自己的项目至网站。但是并没有版本控制的意识,只是当做代码仓库罢了。
得益于此次git课程的学习,算是对了一个项目如何利用git协同协作,提交自己的更新代码至源库,对以后的项目管理更为深刻。
想提一下自己完成的这个程序算法,借用了后续表达式,逆波兰算法,后续表达式可以使得计算机更为方便地计算数据,当然实现来说可能会难一点。在完成这个算法的过程中,为了满足题意:不能出现分数,我自己还主观地认为一年级的朋友应该不会负数,所以自己增加了这样的限定。
最后,完成过后,觉得自己的一些编程习惯还是需要改变,比如有些代码太过于重复,进行提炼为一个方法,增加代码的可重用性,使得代码更为简洁。所以,可能整个程序的代码看起来就是一会儿调用另一个方法。
既然有这样的不断调用其他方法的结构,那么代码中的注释一定不能少。自己也在学着写标准的注释结构。使得阅读代码起来更符合规范,且方便。
比如,类上面的注释使用/**
方法内部的注释使用双斜杠,并且内容需要与符号空一格
还需要学习的东西很多,但是在课程的帮助下也算踏实。
转载于:https://www.cnblogs.com/etron/p/11548636.html
相关资源:JAVA上百实例源码以及开源项目