赞
踩
我们来想一个工厂的生产销售过程,从接单,物料的进厂,上线,加工过程1,加工过程2,加工过程3,包装,下线,出厂,进仓库,转运,售出。这是一整套的流程,而且每个阶段都是可以人为设置更改的,这就是人对这套流程的流程控制。例如在加工过程1中,只要符合规格的物料;在包装中,有的用红色包装,有的用蓝色包装;例如在加工过程3中,要重复进行三次等等。
在整套流程中,每个环节按照顺序依次执行,这对应着程序开发中的顺序结构;在包装中,有的用红色包装,有的用蓝色包装,对应着程序开发中的分支结构;还有需要重复三次,对应着程序开发中的循环结构。
顺序结构
程序从上到下逐行进行执行,中间没有任何判断和跳转。
分支结构
根据条件,选择性的执行某段代码。
有if…else和switch…else两种分支语句。
循环结构
根据循环条件,重复性的执行某段代码
有while、do…while、for三种循环语句
class OrderTest {
public static void main(String[] args) {
System.out.println("进厂");
System.out.println("加工");
System.out.println("出厂");
}
}
语法:
if(条件表达式){
执行代码块
}
class BranchTest {
public static void main(String[] args) {
// if
int success = 85;
if(success > 80){
System.out.println("成绩为优秀");
}
}
}
语法:
if(条件表达式){
执行代码块1
}else{
执行代码块2
}
class BranchTest {
public static void main(String[] args) {
// if-else
if(success < 60){
System.out.println("没有及格");
}else{
System.out.println("及格了!");
}
}
}
语法:
if(条件表达式1){
执行代码块1
}else if(条件表达式2){
执行代码块2
}else if(...){
...
}else if(条件表达式N){
执行代码块N
}else{
执行代码块N+1
}
class BranchTest {
public static void main(String[] args) {
// if-else if-else
if(success >= 90){
System.out.println("成绩很好,很棒!");
}else if((80 <= success) && (success < 90 )){
System.out.println("成绩很不错,但是还有提升的空间!");
}else if((60 <= success) && (success < 80 )){
System.out.println("还可以,但是要努力加油了!");
}else{
System.out.println("你现在很危险!");
}
}
}
然后来做几道练习题:
class BranchTest1 { public static void main(String[] args) { // 练习1 int x = 4; int y = 1; if(x > 2){ if(y > 2) // 这一条不会输出,是因为if语句有一种特殊的原则叫做就近原则 // 这一条语句属于 if(y > 2)。 System.out.println(x + y); // 就近原则只对第一行有约束作用 // 这一条语句属于 if(x > 2) System.out.println("红鲤鱼绿鲤鱼"); }else{ System.out.println("x is" + x); } // 总结: 不要省略大括号,会影响代码可读性 // 练习2 boolean b = true; if(b == false) System.out.println("a"); else if(b) System.out.println("b"); // 匹配到第一条表达式为true的语句就不再往下匹配。 else if(b) System.out.println("c"); else System.out.println("d"); // 练习3 /* * 编写程序,声明2个int型变量并赋值, * 判断两数之和,如果大于等于50,打印"Hello World!" */ int lx3A = 30; int lx3B = 30; if (lx3A + lx3B >=50){ System.out.println("Hello World!"); } // 练习4 /* * 编写程序,声明2个double型变量并赋值。 * 判断第一个数大于10.0,且第二个数小于20.0, * 打印两数之和。 * 否则打印两数之积。 */ double lx4A = 12.34; double lx4B = 12.45; if (lx4A > 10 && lx4B < 20){ System.out.println(lx4A + lx4B); }else{ System.out.println(lx4A * lx4B); } } }
如果只通过单纯的分支结构,显然过于僵硬,输入什么,输出什么都是僵硬的,那么可不可以控制输入来影响输出。这就需要扫描类–scanner。
import java.util.Scanner; class InputTest { public static void main(String[] args) { /* * 岳小鹏参加考试,他爸爸和他说: * 考100分,奖励一个手机; * 考80到99分,奖励一个平板; * 考60到80分,奖励一个主机游戏; * 其他分数就什么也不奖励。 * * 请使用键盘输入岳小鹏的成绩进行判断。 * * 如何进行键盘输入呢? 需要使用Scanner类 * * 1. 导包 impart java.util.Scanner; (写在类外) * 2. 实例化对象 Scanner scan = newScanner(System.in); (System.in 表示从键盘输入)(写在main内) * 3. 调用整型接收成绩 int success = scan.nextInt(); (获取指定类型的变量) (写在需要接收输入的地方) */ Scanner scan = new Scanner(System.in); System.out.println("岳小鹏,你考了多少分呢?"); int success = scan.nextInt(); if(success == 100){ System.out.println("岳小鹏获得了一个*为 Mate30 RS 5G版"); }else if(80<=success && success<=99){ System.out.println("岳小鹏获得了一个*为 MatePad Pro"); }else if(60<=success && success<80){ System.out.println("岳小鹏获得了只狼一部,并戒除游戏考上了清华"); }else{ System.out.println("屁也没有"); } // 释放内存流 scan.close(); } }
scanner除了nextInt这个函数之外,还有什么函数呢?
import java.util.Scanner; class ScannerTest { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请输入你的姓名"); String name = scan.next(); System.out.println("请输入你的年龄"); int age = scan.nextInt(); // nextByte 接收byte,nextShort 接收short,以此类推 System.out.println("请输入你的体重"); // 这里也一样 double weight = scan.nextDouble(); System.out.println("你是否单身"); boolean isOk = scan.nextBoolean(); System.out.println("姓名是: " + name); System.out.println("年龄是: " + age); System.out.println("体重是: " + weight); System.out.println("是否单身: " + isOk); scan.close(); // 如果输入的类型与接收的类型不匹配时,会报异常:InputMismatchException } }
现在,结合键盘录入类Scanner做几道if-else if-else的练习题
import java.util.Scanner; class InputTest1 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); // 练习1 /* *由键盘输入三个整数,分别存储num1,num2,num3,对他们进行排序(使用 if-else if-else),并从小到大输出。 */ System.out.println("请输入num1:"); int num1 = scan.nextInt(); System.out.println("请输入num2:"); int num2 = scan.nextInt(); System.out.println("请输入num3:"); int num3 = scan.nextInt(); if(num1 >= num2){ if (num3 >= num1){ System.out.println(num2+","+num1+","+num3); }else if(num3 <= num2 ){ System.out.println(num3+","+num2+","+num1); }else{ System.out.println(num2+","+num3+","+num1); } }else{ if (num3 >= num2){ System.out.println(num1+","+num2+","+num3); }else if(num3 <= num1 ){ System.out.println(num3+","+num1+","+num2); }else{ System.out.println(num1+","+num3+","+num2); } } // 练习2 /* * 狗的年龄与人的年龄换算: * 狗的前两年一年相当于人的10.5岁 * 之后每一岁相当于人的四岁。 * 编写一个程序,获取用户输入狗的年龄 * 通过程序展示对应人类的年龄。 * 如果输入负值,显示一个提醒。 */ System.out.print("请输入狗的年龄:"); double lx5Age = scan.nextDouble(); if (lx5Age >= 0 && lx5Age <=2){ lx5Age = lx5Age * 10.5; System.out.println("相当于人类的"+lx5Age+"岁"); }else if(lx5Age > 2){ lx5Age = 21 + (lx5Age - 2) * 4; System.out.println("相当于人类的"+lx5Age+"岁"); }else{ System.out.println("请输入大于等于0的数字"); } scan.close(); } }
然后再多来一道附加题:
假设你想开发一个玩彩票的游戏,程序随机地产生一个两位数的彩票,提示用户输入一个两位数,然后按照下面的规则判定用户是否能赢。
(1)如果用户输入的数匹配彩票的实际顺序,奖金10000元
(2)如果用户输入的所有数字匹配彩票的所有数字,奖金3000元
(3)如果用户输入的一个数字仅满足顺序的情况下匹配彩票的一个数字,奖金1000元
(4)如果用户输入的一个数字仅满足非顺序的情况下匹配彩票的一个数字,奖金500元
(5)若不匹配,彩票作废。
例如,随机生成一个数字:45
用户输入45,则奖金10000元。
用户输入54,则奖金3000元。
用户输入4*或*5,则奖金1000元。
用户输入*4或5*,则奖金500元。
其他情况彩票作废。
首先,要解决一个问题:怎么生成随机数?
如何获得一个随机数,就需要用到另外的一个类:Math。
import java.util.Scanner; class RandomTest { public static void main(String[] args) { // 首先随机生成一个两位数 // Math位于java.lang包下,此包下的所有类不需要impost引入 int number = (int)(Math.random() * 90 + 10); // Math.random() 会随机生成一个位于[0,1)的数 // Math.random() * 90 + 10 会生成一个[10,100)的数 // 得到随机数的十位和个位 int numberShi = number/10; int numberGe = number%10; // 用户输入一个两位数 Scanner input = new Scanner(System.in); System.out.print("请输入一个两位数:"); int guess = input.nextInt(); // 获取用户输入数的十位和个位 int guessShi = guess/10; int guessGe = guess%10; if(number == guess){ System.out.println("奖金10 000元"); }else if(numberShi == guessGe && numberGe == guessShi){ System.out.println("奖金3 000元"); }else if(numberShi==guessShi || numberGe == guessGe){ System.out.println("奖金1 000元"); }else if(numberShi==guessGe || numberGe == guessShi){ System.out.println("奖金500元"); }else{ System.out.println("没中奖"); } System.out.println("中奖号码是:" + number); input.close(); } }
OK,现在把视线放到我们最开始if-else if-else举得那个例子那里,现在我们有了另外一个需求:
100分的评分为S;
90-99分评分为A;
60分以下为D-;
以此类推。
如果使用if语句的话:
if(x == 100){
System.out.println("S");
}else if(x>=90 && x<100){
System.out.println("A");
}else if(x>=80 && x<90){
System.out.println("B");
}else if(...){
...
}else{
System.out.println("请输入1-100");
}
难道要写这么多个else if吗,有没有简单一点的方法,这就可以用到另外一个分支语句–switch-case语句。
switch(表达式){
case 常量1:
语句1;
// break;
case 常量2:
语句2;
// break;
...
case 常量N:
语句N;
// break;
default:
语句N+1;
// break;
}
然后使用switch-case语句来实现成绩评分:
import java.util.Scanner; class SwitchTest { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请输入成绩:"); int number = scan.nextInt(); int numberGe = number / 10; switch(numberGe){ case 10: System.out.println("评分为S"); break; case 9: System.out.println("评分为A"); break; case 8: System.out.println("评分为B"); break; case 7: System.out.println("评分为C"); break; case 6: System.out.println("评分为D"); break; default: System.out.println("评分为D-"); } scan.close(); } }
注意点1:case语句块后不加break的话会导致一旦匹配某一条case语句,就会开始执行从这条语句块之后的所有语句块,直到遇到break或switch语句块结尾。
例如:输入70,应该输出评分C,但是如果将break都注释掉,则会输出:
评分为C
评分为D
评分为D-
注意点2:switch表达式只能是:byte,short,int,char,枚举类型和string。
注意点3:case后必须跟常量
注意点4:default可选,且位置可控,如果不在末位的话,记得要加break
练习题:
import java.util.Scanner; class SwitchTest1 { public static void main(String[] args) { Scanner scan = new Scanner(System.in); /** * 1.使用是switch把小写类型的char型转为大写, * 只转换a,b,c,d,e,其他的输出‘other’ */ System.out.println("请输入字母:"); String word = scan.next(); char c = word.charAt(0); switch(c){ case 'a': c = 'A'; break; case 'b': c = 'B'; break; case 'c': c = 'C'; break; case 'd': c = 'D'; break; case 'e': c = 'E'; break; default: System.out.println("other"); } System.out.println(c); /** * 2.根据指定月份,打印该月份所属的季节。 */ System.out.println("请输入月份:"); int month = scan.nextInt(); switch(month){ case 3: case 4: case 5: System.out.println("春季"); break; case 6: case 7: case 8: System.out.println("夏季"); break; case 9: case 10: case 11: System.out.println("秋季"); break; case 12: case 1: case 2: System.out.println("冬季"); break; default: System.out.println("请输入1-12"); } /** * 3.从键盘上输入2020年的月和日, * 然后输出输入日期为2020年的第几天。 */ System.out.println("请输入月份:"); int lx3Month = scan.nextInt(); System.out.println("请输入日期:"); int lx3Day = scan.nextInt(); int sumDays = 0; switch(lx3Month){ case 12: sumDays += 30; case 11: sumDays += 31; case 10: sumDays += 30; case 9: sumDays += 31; case 8: sumDays += 31; case 7: sumDays += 30; case 6: sumDays += 31; case 5: sumDays += 30; case 4: sumDays += 31; case 3: sumDays += 29; case 2: sumDays += 31; case 1: sumDays += lx3Day; default: System.out.println("请输入1-12"); } System.out.println(sumDays); scan.close(); } }
语法:
for(初始化条件;循环条件;迭代条件){
循环体
}
去看一下最开始的工厂流程,加工过程3要重复执行三次,现在我们来简化成代码,如果不使用循环结构的话,也许可以这样写:
class ForTest {
public static void main(String[] args) {
System.out.println("Hello World!");
System.out.println("Hello World!");
System.out.println("Hello World!");
}
}
如果使用循环结构的话:
class ForTest {
public static void main(String[] args) {
for(int i = 0;i < 3;i ++){
System.out.println("Hello World!");
}
}
}
练习题:
import java.util.Scanner; class ForTest { public static void main(String[] args) { /** * 练习1 * 写出这段程序的运行结果, * 以来理解for循环的执行流程 */ int num = 1; for (System.out.println('a');num <= 3;System.out.println('c'),num ++){ System.out.println('b'); } /** * 练习2 * 遍历100以内的偶数 */ for(int a = 0;a <= 100; a += 2){ System.out.println(a); } /** * 练习3 * 循环输出1-150,每一行打印一个值, * 3的倍数后打印foo * 5的倍数后打印biz * 7的倍数后打印baz * 注:可以重复追加 */ for(int b = 1;b <= 150;b ++){ String s = b + ""; if (b % 3 == 0){ s += " foo"; } if (b % 5 == 0){ s += " biz"; } if (b % 7 == 0){ s += " baz"; } System.out.println(s); } /** * 练习4 * 输入两个正整数m和n,求其最大公约数和最小公倍数 * 12和20的最大公约数是4,最小公倍数是60 */ Scanner scan = new Scanner(System.in); System.out.println("请输入第一个正整数:"); int m = scan.nextInt(); System.out.println("请输入第二个正整数:"); int n = scan.nextInt(); for(int lx4i = Math.min(m, n);lx4i >= 1 ;lx4i -- ){ if(m % lx4i == 0 && n % lx4i == 0){ System.out.println("最大公约数:" + lx4i); break; } } for (int lx4j = Math.max(m, n);lx4j <= m * n;lx4j ++ ){ if(lx4j % m == 0 && lx4j % n == 0){ System.out.println("最小公倍数:" + lx4j); break; } } /** * 练习5 * 打印1-100之间的奇数和 */ int sum = 0; for(int lx5I = 1;lx5I <= 100;lx5I += 2){ sum += lx5I; } System.out.println("1-100奇数和为:" + sum); /** * 练习6 * 打印1-100之间所有是7的倍数的整数的个数与和 */ int number = 0; sum = 0; for(int lx6I = 0; lx6I <= 100;lx6I ++){ if(lx6I % 7 == 0){ number ++; sum += lx6I; } } System.out.println("和为:" + sum); System.out.println("个数为:" + number); /** * 练习7 * 输出1000以内所有的水仙花数。 * 例如:153=1^3+5^3+3^3 */ for(int lx7I = 100;lx7I < 1000;lx7I ++){ int lx7Ibai = lx7I / 100; int lx7Ishi = lx7I % 100 /10; int lx7Ige = lx7I % 10; if (lx7Ibai*lx7Ibai*lx7Ibai+lx7Ishi*lx7Ishi*lx7Ishi+lx7Ige*lx7Ige*lx7Ige == lx7I ){ System.out.println(lx7I); } } scan.close(); } }
到这里,大家对for循环有了初步的理解,接着我们来仔细说一下break语句以及他的孪生兄弟continue语句。
break可以用在switch-case语句和循环结构中,可以终止所在语句块的执行,跳转到语句块外。
continue比break温柔一些,他只能作用在循环结构中,并且只能终止当前循环。
来看一下他们的执行图
然后看两个例子:
class ContinueTest { public static void main(String[] args) { for(int i = 0;i < 5;i ++ ){ if(i == 3){ break; } System.out.println(i); } System.out.println("-----"); for(int j = 0;j < 5;j ++ ){ if(j == 3){ continue; } System.out.println(j); } } } 0 1 2 ----- 0 1 2 4
break和continue语句还有一个名称,叫做循环控制语句,他们可以控制循环是否进行。
现在我们可以产生循环结构,可以控制循环结构了,那么我们是不是可以写一个无限的循环呢,只让他在特定的情况下结束循环。比如我们在上面写过一个猜彩票的小游戏,它允许一次只可以玩一次,那么该怎么让我们可以无限玩呢?
这就需要我们另一个循环语句–while语句。
语法:
初始化条件
while(条件表达式){
循环体;
迭代条件;
}
他的执行流程与for循环的执行流程一致,就不重复了。
class WhileTest {
public static void main(String[] args) {
int i = 5; // 初始化条件
while(i >= 0){ // 条件表达式
System.out.println(i); // 循环体
i --; // 迭代条件
}
}
}
然后我们来看看最开始所说的while循环具有的特性:
import java.util.Scanner;
class WhileTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int i = 0;
while(true){
System.out.println("请输入一个数:");
i = scan.nextInt();
if (i == 10){
break;
}
}
scan.close();
}
}
这样的话,只有我们输入10,这个循环才会结束,否则会一直执行。
然后改进一下我们的猜彩票小游戏,改成猜数小游戏。
import java.util.Scanner; class WhileTest1 { public static void main(final String[] args) { // 首先随机生成一个两位数 final int number = (int)(Math.random() * 90 + 10); // 实例化对象 Scanner input = new Scanner(System.in); int guess = 0; int num = 0; while(true){ num ++; System.out.print("请输入一个两位数:"); guess = input.nextInt(); if(guess == number){ System.out.println("恭喜你猜对了,你一共猜了"+num+"次!"); break; }else if(guess > number){ System.out.println("你猜大了!"); }else{ System.out.println("你猜小了!"); } } input.close(); } }
然后,while语句还有一个兄弟-do–while语句。
语法:
初始化条件;
do{
循环体;
迭代条件;
}while(条件表达式)
这个语句的条件表达式是放在最后的,也就是说第一次循环体的执行无序进行条件判断。
流程图也是独具一格,不过太特殊的东西一般用的都不多,这里就不再细细阐述,就需要记住他无论满不满足条件表达式都可以执行一次循环体。
嵌套不是一个新的知识点,在说if语句时我们就使用过在if中嵌套if的用法。
嵌套循环也就是把一个循环语句放到另一个循环语句中。
class NestedLoop{
public static void main(String[] args) {
for(int i = 0;i < 5;i ++){
for(int j = 0;j < 3;j ++){
System.out.print("* ");
}
System.out.println();
}
}
}
或者
class NestedLoop{
public static void main(String[] args) {
int a = 0;
while(a < 5){
int b = 0;
while(b < 3){
System.out.print("* ");
b ++;
}
System.out.println();
a ++;
}
}
}
还有
class NestedLoop{
public static void main(String[] args) {
int x = 0;
do{
int y = 0;
do{
System.out.print("* ");
y ++;
}while(y < 3);
System.out.println();
x ++;
}while(x < 5);
}
}
这几个看起来,果然还是for循环的可读性更高。
然后写个九九乘法表:
class NestedLoop{
public static void main(String[] args) {
for(int i = 1;i < 10;i ++){
for(int j = 1;j <= i;j ++){
System.out.print(i + "*" + j + "=" + i*j + "\t");
}
System.out.println();
}
}
}
外层循环控制行数,内层循环控制列数。
然后我们用“*”打印一个菱形。
* * * * * * * * * * * * * * * * * * * * * * * * * ---------- class NestedLoop{ public static void main(String[] args) { // 上半部分 for (int i = 0; i < 5; i++) { // 输出“-” for (int j = 0; j < 4 - i; j++) { System.out.print(" "); } // 输出“* ” for (int k = 0; k < i + 1; k++) { System.out.print("* "); } System.out.println(); } // 下半部分 for (int i = 0; i < 4; i++) { for (int j = 0; j < i + 1; j++) { System.out.print(" "); } for (int k = 0; k < 4 - i; k++) { System.out.print("* "); } System.out.println(); } } }
练习题:
class NestedLoop{ public static void main(String[] args) { /** * 练习1 * 输出1-100以内所有的质数 * 思路:这个数模除1-它本身之间所有的数,都有余数的就是质数。 */ boolean isFlag; //引入旗值的概念。 for(int lx1I = 2;lx1I <= 100;lx1I ++){ isFlag = true;// 旗值默认为true for(int lx1J = 2;lx1J < lx1I;lx1J ++){ if (lx1I % lx1J == 0){ isFlag = false; // 如果有可以完全模除的数,就把旗值改为false } } if(isFlag){ // 最后判断旗值是不是true,是的话表示没有可以完全模除的数 System.out.println(lx1I); } } /** * 练习2 * 输出1-100以内所有的完数 * 完数就是一个数所有的因子相加等于这个数 * 例如:6的因子是1,2,3 1+2+3 等于 6 */ for(int lx2I = 1;lx2I <= 1000;lx2I ++){ int factor = 0; // 使用一个变量来对待测数的因子进行加和。 for(int lx2J = 1;lx2J <= lx2I / 2 ;lx2J ++){ if(lx2I % lx2J== 0){ factor += lx2J; } } if(lx2I == factor){ // 如果加和后的数等于待测数,表示这个数是完数。 System.out.println(lx2I); } } } }
引入旗值这个概念可以很方便的理解,但是如果范围太大,这个代码运行的时间就太长了,时间复杂度是O(n2),空间复杂度是O(1)。
现在尝试对他进行一些优化,降低他的运行的时间:
boolean isFlag; //引入旗值的概念。
for(int lx1I = 2;lx1I <= 100;lx1I ++){
isFlag = true;// 旗值默认为true
for(int lx1J = 2;lx1J < lx1I;lx1J ++){
if (lx1I % lx1J == 0){
isFlag = false; // 如果有可以完全模除的数,就把旗值改为false
break; // 只需要增加一个break,也就是说只要旗值变了一次,就没必要进行下面的循环了
}
}
if(isFlag){ // 最后判断旗值是不是true,是的话表示没有可以完全模除的数
System.out.println(lx1I);
}
}
优化二:
boolean isFlag; //引入旗值的概念。
for(int lx1I = 2;lx1I <= 100;lx1I ++){
isFlag = true;// 旗值默认为true
for(int lx1J = 2;lx1J <= Math.sqrt(lx1I);lx1J ++){ // 对数开方后,主要对最小因数进行遍历
if (lx1I % lx1J == 0){
isFlag = false; // 如果有可以完全模除的数,就把旗值改为false
break; // 只需要增加一个break,也就是说只要旗值变了一次,就没必要进行下面的循环了
}
}
if(isFlag){ // 最后判断旗值是不是true,是的话表示没有可以完全模除的数
System.out.println(lx1I);
}
}
补充:循环控制语句的标签用法
循环控制语句可以搭配标签语句,在跳出时会自动跳到标签所在的位置,类似于goto语句。
label:for(int i = 1;i <= 4;i ++){
for(int j = 1;j <= 10;j ++){
if(j % 4 == 0){
break label;
}
System.out.print(j);
}
System.out.println();
}
这样在执行break的时候,直接把外层循环也kill掉了。
continue同理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。