程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例相关的知识,希望对你有一定的参考价值。


先来看一下<<面向对象编程>>这本教材第一章第16个练习给的代码:

package chapter2.e16;

import java.util.Scanner;

public class TwoLoopTest

public static void main(String[] args)
// TODO Auto-generated method stub
menu();
play();


private static void menu()
// TODO Auto-generated method stub
System.out.println("**********欢迎使用计算器**********");
System.out.println("1.加法运算");
System.out.println("2.减法运算");
System.out.println("3.乘法运算");
System.out.println("4.除法运算");
System.out.println("5.取余运算");
System.out.println("6.退出");
System.out.println("*******************************");


private static void play()
// TODO Auto-generated method stub
int i = 0;
double a = 0.0;
double b = 0.0;
Scanner sc = new Scanner(System.in);
System.out.println("输入您要进行的操作:");
i = sc.nextInt();
while (true)
switch (i)
case 1:
System.out.println("输入两个数进行加法");
a = sc.nextDouble();
b = sc.nextDouble();
System.out.println("计算结果为:" + (a + b));
break;
case 2:
System.out.println("输入两个数进行减法");
a = sc.nextDouble();
b = sc.nextDouble();
System.out.println("计算结果为:" + (a - b));
break;
case 3:
System.out.println("输入两个数进行乘法");
a = sc.nextDouble();
b = sc.nextDouble();
System.out.println("计算结果为:" + (a * b));
break;
case 4:
System.out.println("输入两个数进行除法");
a = sc.nextDouble();
b = sc.nextDouble();
System.out.println("计算结果为:" + (a / b));
break;
case 5:
System.out.println("输入两个数进行取余");
a = sc.nextDouble();
b = sc.nextDouble();
System.out.println("计算结果为:" + (a % b));
break;
case 6:
System.out.println("*********谢谢使用!*********");
break;
default:
System.out.println("输入有误!");

menu();
play();


简单地看好像没啥问题,我们运行一下:

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_break


嗯?居然报错了?!看一下代码:

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_switch_02


原来是要一个数一个数地输入,好吧,那我先退出程序:

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_代码规范_03


居然无法退出?!原来是case 6没有break!但是,你以为把break加上就可以了吗?

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_java_04


no!一个break只是跳出了case语句,不能跳出while循环!

HOW TO DO?

  1. ​​增加输入判断的函数,输入不是整数则打回​​
  2. ​​case语句重复内容过多,把他们提出来!​​
  3. ​​一次性退出while循环!​​

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_case_05

增加输入判断的函数,输入不是整数则打回

原程序中,如果输入字母或特殊字符时,会报错:

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_break_06


来看看输入语句:

Scanner sc = new Scanner(System.in);  
i = sc.nextInt();

很明显,nextInt()只能接受整型,类型不对自然会报错,怎么解决?

加一个输入判断的函数:

private static int judgeInput() 
int number = 0;
Scanner sc = new Scanner(System.in);
if (sc.hasNextInt())
number = sc.nextInt();

else
System.out.println("Please check and input again");
menu();

return number;

如果输入不是整数,则重新输入;输入正确后直接return刚刚输入的值

case语句重复内容过多,把他们提出来!

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_break_07


让我们把这些重复的语句全部提出来!

System.out.println("Please enter the first number:");
a = sc.nextDouble();
System.out.println("The second number:");
b = sc.nextDouble();

这里顺手加上提示语句,好让用户明白是输入两次

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_switch_08


但是case 6不需要输入,所以这里我们加一句判断:

if (i != 6) 
System.out.println("Please enter the first number:");
a = sc.nextDouble();
System.out.println("The second number:");
b = sc.nextDouble();

不然退出之前还要输入两个数

一次性退出while循环!

程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_代码规范_09


程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例_case_10


这时,我们给while循环加上一个标记:

circulatory:
while (true)
switch (i)
case 6:
System.out.println("*********谢谢使用!*********");
break circulatory;

这样就可以直接跳出while循环了

其实这些东西都很细节,但是往往越是细节的地方,就越是要注意

下面是我修改好的代码,其中还有很多可以修改的地方,欢迎大家批评指正:

package project1;

import java.util.Scanner;

/**
* @author 郑博培
*/
public class CalculatorDemo
public static void main(String[] args)
menu();


private static void menu()
System.out.println("**********Calculator Menu**********");
System.out.println("1.加法运算");
System.out.println("2.减法运算");
System.out.println("3.乘法运算");
System.out.println("4.除法运算");
System.out.println("5.取余运算");
System.out.println("6.退出");
System.out.println("*******************************");
System.out.println("输入您要进行的操作:");
play(judgeInput());


private static int judgeInput()
int number = 0;
Scanner sc = new Scanner(System.in);
if (sc.hasNextInt())
number = sc.nextInt();
else
System.out.println("Please check and input again");
menu();

return number;


private static void play(int i)
double a = 0.0;
double b = 0.0;
Scanner sc = new Scanner(System.in);
circulatory:
while (true)
if (i != 6)
System.out.println("Please enter the first number:");
a = sc.nextDouble();
System.out.println("The second number:");
b = sc.nextDouble();

switch (i)
case 1:
System.out.println("两个数进行加法");
System.out.println("计算结果为:" + (a + b));
break;
case 2:
System.out.println("两个数进行减法");
System.out.println("计算结果为:" + (a - b));
break;
case 3:
System.out.println("两个数进行乘法");
System.out.println("计算结果为:" + (a * b));
break;
case 4:
System.out.println("两个数进行除法");
System.out.println("计算结果为:" + (a / b));
break;
case 5:
System.out.println("两个数进行取余");
System.out.println("计算结果为:" + (a % b));
break;
case 6:
System.out.println("*********谢谢使用!*********");
break circulatory;
default:
System.out.println("输入有误!");

menu();



拿什么心情来阅读我的代码(程序员的必备心理技能)

原文首发于我的微信公众号:GeekArtT .

阅读源代码的开始阶段,最好从感兴趣、自己有直观感受且有相对丰富准确的文档的项目开始。如同最开始阅读数学证明,最好从浅显易懂的教材开始,之后再开始最前沿的paper阅读。

 

阅读源代码需要同阅读证明一样的耐心,甚至更多。数学的定义或许就在前一页,可是源代码的某个新的类却需要你不断地Google,进而找到适合自己的关于原始概念的定义论述。

 

阅读源代码一定要放空自己的心,要做好精心死磕的准备。至少要在心理上给自己留出足够多的空间与时间。大不了拿出大段时间去浪费,去阅读、去死磕、去慢慢地把玩这个小片段的内容。(或者更成熟的想法是,完全集中注意力在自己的阅读工作上,根本不去关心它所需要花费的时间。)在这个阶段,最好拿出最为自私的气魄,TMD全世界的事情和期望都不管了,我就要在这个小小的代码片段所形成的逻辑框架里慢慢破解我的问题。

 

能否继续下去之后的阅读,这个阶段的心理就是绝对的分水岭。不要去想什么意义不意义,不要去思考什么浮躁的进度或者世界期望、又或是想什么此生也就如此的屁话,那些“存在”的问题是在决定是否开始阅读的时候考虑的,而不是阅读之中。在阅读的过程中,就如同已经在雪山上的登山者,已经毫无退路,最优做法就是不要把自己的精力浪费在任何无关事情之上,而是把所有力气花在问题攻坚上。

 

在这一刻,研究者是世界的王者。世界都必须为他而停止,他要拥有至高无上的心理信心。因为,一名研究者的珍贵价值之一,便是能够完全吃透繁杂深奥的问题和论述。而这项工作兼具思维的复杂性与劳作的漫长艰辛。他需要将自己的智慧挖掘到最深处。并在同时,他要像一名在流水线上劳作的工人,经历无意义的重复劳作和蛮长时间的煎熬。因为破解这些谜题,需要一次又一次西西弗斯式的基础工作。不断地提出一个猜想,然后找寻证据去证明或者否定,然后继续下一个问题,又或是提出另一个思路,继续做探索和验证。

 

而思路的建立或者潜在可行方案的直觉,都会牢牢建立在你对某个类或者某个文件的认知和相应定义的理解上。例如,向一个初学Android的人直接抛出PreferenceManager的概念会让人一头雾水。你可能会有潜在的猜测,偏好设置?仅仅是某个setting文件的管理?又或是神马?可是为什么在使用它的时候又会用到工厂模式?相应的edit是要去编辑神马呢?

 

不,这些都只是你一厢情愿的猜测。甚至,你的猜得越远,错得越厉害。而错误的起步,当然就是源自于你对PreferenceManager定义的猜测。这是代码世界中更加tricky的一个坑。不同于数学证明,由于数学领域的大多数术语都是稀奇古怪的或者生僻从未听说过,在阅读证明时,我们反而能更加警觉、仔细地去按图索骥,找到定义最原始的出处,去确保自己的理解无误。而在代码的世界里,由于命名需要可理解、通俗易懂,大多数的命名都会找寻生活中常见的词语。而这里,便是入坑的开始。

 

如果你对人文历史有足够充分的研究,你便会知道日常用语的多意性以及它所带来的后果的惨痛性。当在代码中充斥着各种似曾相识的名字时,你便会被这个“名”(名字)所迷惑。你会下意识地根据自身的经验去猜测它的作用和所指。虽然好的代码规范总是要求对命名要做到避免模糊和误用的特性,但你凭什么知道你阅读的这份代码遵从了它呢?

 

所以,真正正确的打开方式是,你必须确保你对其中的每一个术语都真正做到了知道它的原始定义所在。你必须要有可信程度极高的证据来支持你对定义的理解:最可信的莫过于定义这个术语的源代码,其次是它的官方API文档说明。你不可以用自己的历史经验来作为正确理解的论据。相反,你需要把这份艰辛的苦力做好、做扎实,为每一个术语找到最原始的依据,然后根据这个依据来确保自己的理解正确。

 

有了“术语考据”这一步的坚实基础,之后的代码阅读就会相对轻松。例如在上面的例子中,如果你查询过Android文档,查看过StackOverflow上的解析,你便会发现这个PreferenceManager是特有的存储临时信息(方便App内部沟通共享)的方式。那么,之后运用工厂模式的理由就变得显而易见了。所以,和数学证明的研读极其类似,找准了定义、吃准了最原始的“名”背后的“道”(真正所指),就能够为之后的过程起到四两拨千斤的巨大作用。

 

当然,这一过程无疑是费时费力的。往往,一个下午的尝试也就只能换取一行代码的正确理解。而身处这一耗尽心力的过程中,你绝望地感觉到,似乎所有的工作都毫无进展。然而,如同对数学证明的学习,这也正是其价值所在。没有多少人能够继续这种耗时耗力的孤独坚持,而这每一步的微小进展,其背后都有难以估量的时间与大量尝试的累积。所以在这一刻,阅读者需要在心里树立起毫无理由的自信心,让世界为自己去停止,让他人的期望在此刻消失。此时此刻,只有代码的破解与思维的运转。

 

如此耐心劳作,方能习得最精妙的技术,最坚实的设计。

 

 

 


 

如果你喜欢我的文章或分享,请长按下面的二维码关注我的微信公众号,谢谢!

 

以上是关于程序员必备技能!给别人的代码挑错之Java教材上的"计算器"实例的主要内容,如果未能解决你的问题,请参考以下文章

拿什么心情来阅读我的代码(程序员的必备心理技能)

程序员必备技能之多线程的安全机制

程序猿必备技能之MySQL高级篇

《Java Web开发实战》——Java工程师必备干货教材

程序猿必备技能之MySQL基础篇

程序员必备技能之SpringBoot的自动装配原理,很详细,建议收藏!!!