1.程序流程控制
用来控制程序中各语句执行顺序,可把语句组合成能完成一定功能的逻辑模块;采用结构化程序设计中规定的三种基本流程。
顺序结构:程序从上到下逐步执行,中间无任何跳转和判断。
分支结构:根据条件,选择性执行某段代码;有if...else和switch-case两种分支语句。
循环结构:根据循环条件,重复执行某段代码;有while、do...while和for三种循环;JDK1.5之后添加了foreach循环,方便遍历集合、数组元素。
2.顺序结构
Java中定义成员变量时采用合法的前向引用。
public class Test{
// 顺序执行,先赋值,后计算num2的值
int num1 = 12;
int num2 = num1 + 4;
}
3.分支结构
3.1.if-else分支结构
// if结构
if(条件表达式){
语句块;
}
// if-else结构
if(条件表达式){
语句块1;
}else{
语句块2;
}
// 多条件if-else if语句
if(表达式1){
语句1;
}else if(表达式2){
语句2;
}else if(表达式3){
语句3
}else{
语句n;
}
// 嵌套if结构
if(条件表达式){
if(条件表达式){
语句块;
}
}else{
语句块2;
}
3.2.if-else说明
条件表达式必须是布尔表达式(关系表达式或逻辑表达式)、布尔变量;语句块只有一条执行语句时,一对{}可以省略,但建议保留;if-else语句结构,根据需要可以嵌套使用;当if-else结构是“多选一”时,最后的else是可选的,根据需要可以省略。
public static void main(String[] args) {
int heartBeat = 79;// 健康
int score = 88;// 成绩
if(score > 80){
System.out.println("优秀");
}
if(heartBeat < 60){
System.out.println("进一步检查");
}else if(heartBeat > 100){
System.out.println("尽快去检查");
}else {
System.out.println("检查结束");
}
}
多条件表达式之间互斥或无交集关系,判断执行语句声明上下顺序无所谓; 多条件表达式有交集关系,需根据实际情况,考虑各结构声明在上下顺序;多条件表达式有包含关系,需将范围小的声明在范围大的上面,否则范围小的没机会执行。
// if的条件有交集,范围小的在上方
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入小鹏成绩:(0-100)");
double sorce = input.nextDouble();
if(sorce == 100.0){
System.out.println("奖励一辆BWM");
}else if(sorce >= 80){
System.out.println("奖励一台iphone");
}else if(sorce >= 60){
System.out.println("奖励一个iPad");
}else{
System.out.println("没有奖励");
}
}
if-else结构可嵌套使用;if-else结构只有一条可省略括号。
// if-else结构嵌套使用把三个数按从大到小排序
public class IfTest02 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入三个整数:");
int num1 = input.nextInt(),
num2 = input.nextInt(), num3 = input.nextInt();
int temp;
if(num1 >= num2){
if(num3 >= num1){
System.out.println(num3+","+num1+","+num2);
}else if(num3 <= num2){
System.out.println(num1+","+num2+","+num3);
}else {
System.out.println(num1+","+num3+","+num2);
}
}else {
if(num3 >= num2){
System.out.println(num3+","+num2+","+num1);
}else if(num3 <= num1){
System.out.println(num2+","+num1+","+num3);
}else {
System.out.println(num2+","+num3+","+num1);
}
}
}
3.3.Scanner和Random
从键盘获取不同类型的变量,需要使用Scanner类,使用步骤如下:
导包:impot java.util.scanner;
Scanner的实例化:Scanner scan = new Scanner(System.in);
获得键盘输入的数据(int now = input.newtInt();(String next()获得一个字符串;int nextInt()获得一个整型数值),来获取指定类型的变量。
注意:需要根据相应的方法,来输入指定类型的值,如果输入的数据类型与要求的类型不匹配时,会报异常:InputMisMatchExcetion导致程序终止。
package com.dhangguogu.test;
//1.导包:import java.util.Scanner;
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
// 2.Scanner的实例化
Scanner input = new Scanner(System.in);
// 3.调用Scanner类的相关方法
System.out.println("输入你的名字:");
String name = input.next();// 获取String类型的字符串
System.out.println("请入你的年龄:");
int age = input.nextInt();// 获取int类型的整数
System.out.println("请入你的体重:");
double weight = input.nextDouble();// 获取double类型的浮点数
System.out.println("请入你的是否看中我(false/true):");
boolean blean = input.nextBoolean();// 获取boolean值
System.out.println("名字:" + name + "\t年龄:" + age + "\t体重:" + weight + "\t看中:" + blean);
// 对于char型的获取,Scanner没有提供相关的方法。只能获取一个字符串
System.out.println("请输入你的性别:(男/女)");
String gender = input.next();// "男"
char genderChar = gender.charAt(0);// 获取gender索引为0位置上的字符
System.out.println(genderChar);
}
}
需要获取随机数使用Random类。
获取[a,b]区间的随机整数公式:(int)(Math.random() * (b - a + 1) + a)。
public static void main(String[] args) {
//获取一个随机数:10-99
int value = (int)(Math.random()*90 + 10);//[0.0,1.0]-->[0.0,90]-->[10-99]
System.out.println(value);
//公式随机数区间:[a,b]:(int)(Math.random() * (b - a + 1) + a)
}
3.4.Switch-case分支结构
switch(表达式){
case 常量1:
执行语句1;
//break;
case 常量2:
执行语句2;
//break;
...
case 常量n:
执行语句n;
//break;
default:
语句:
//break;
}
3.4.1.Switch-case结构相关规则
switch(表达式)中表达式的值必须是下述几种类型之一:byte,short,char,int,枚举 (jdk 5.0),String (jdk 7.0);case子句中的值必须是常量,不能是变量名或不确定的表达式值;同一个switch语句,所有case子句中的常量值互不相同;break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺序执行到switch结尾;default子句是可任选的。同时,位置也是灵活的。当没有匹配的case时,执行default。
public static void main(String[] args) {
String season = "summer";
switch (season) {
case "spring":
System.out.println("春暖花开");
break;
case "summer":
System.out.println("夏日炎炎");
break;
case "autumn":
System.out.println("秋高气爽");
break;
case "winter":
System.out.println("白雪皑皑");
break;
default:
System.out.println("输入有误");
break;
}
}
根据switch表达式中的值,依次匹配各个case中的常量。一旦匹配成功,则进入相应的case结构中,调用其执行语句;当调用完执行语句以后,则仍然继续向下执行其他case结构中的执行语句,直遇到break关键字或此switch-case结构末尾为止结束。
// 输入年、月、日,判断是当年第几天
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入年份");
int year = input.nextInt();
System.out.println("请输入月份");
int month = input.nextInt();
System.out.println("请输入日期");
int day = input.nextInt();
int sumDays = 0;
switch (month) {
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 += 28;
if((year % 4 == 0 && year % 100 != 0)||year % 400 == 0){
sumDays += 29;
}else {
sumDays += 28;
}
case 2:
sumDays += 31;
case 1:
sumDays += day;
}
System.out.println(year+"年"+month+"月"+day+"日是第"+sumDays+"天");
}
3.5.if-else和switch-case比较
凡是使用switch-case的结构,都可以转化为if-else。反之,不成立;我们写分支结构时,既可以使用switch-case(switch的取值较少),又可以使用if-else时,优先选择使用switch-case,执行效率稍高。
相同点:都能处理多分支条件的结构。
不同点:switch结构只能处理等值条件的判断,多重if结构适合变量处于某个连续区间的情况,判断条件是离散值,用switch。如果判断分支多,用switch。否则用if - else if。
/*
根据出生日期计算星座。
白羊:0321~0420 天秤:0924~1023
金牛:0421~0521 天蝎:1024~1122
双子:0522~0621 射手:1123~1221
巨蟹:0622~0722 摩羯:1222~0120
狮子:0723~0823 水瓶:0121~0219
处女:0824~0923 双⻥:0220~0320
例如:出生日期:0609(6月9日),则对应的是双子座。
铺垫:一个四位数,怎么求出前两位和后两位。
/100结果就是前两位,%100结果就是后两位。
*/
public static void main(String[] args) {
System.out.println("请输入您的出生日期(如0123表示1月23日)");
Scanner sc = new Scanner(System.in);
int monthday = sc.nextInt();//0123
int month = monthday/100;//月份
int day = monthday%100;//日期
String xingzuo = "";
switch (month) {
case 1:
xingzuo = day < 21 ?"摩羯座" : "水瓶座";
break;
case 2:
xingzuo = day < 20 ?"水平座" : "双⻥座";
break;
case 3:
xingzuo = day < 21 ?"双⻥座" : "白羊座";
break;
case 4:
xingzuo = day < 21 ?"白羊座" : "金牛座";
break;
case 5:
xingzuo = day < 22 ?"金牛座" : "双子座";
break;
case 6:
xingzuo = day < 22 ?"双子座" : "巨蟹座";
break;
case 7:
xingzuo = day < 23 ?"巨蟹座" : "狮子座";
break;
case 8:
xingzuo = day < 24 ?"狮子座" : "处女座";
break;
case 9:
xingzuo = day < 24 ?"处女座" : "天秤座";
break;
case 10:
xingzuo = day < 24 ?"天秤座" : "天蝎座";
break;
case 11:
xingzuo = day < 23 ?"天蝎座" : "射手座";
break;
case 12:
xingzuo = day < 22 ?"射手座" : "摩羯座";
break;
default:
break;
}
4.循环结构
在某些条件满足的情况下,反复执行特定代码的功能。循环语句分为:for循环、while循环和do-while循环,由四部分组成:初始化部分、循环条件部分、循环体部分和迭代部分。
4.1.for循环
for(①初始化条件;②循环条件;④迭代条件){
③循环体
}
①初始化条件;②循环条件;③循环体;④迭代条件。
执行过程:①-②-③-④-②-③-④-...-②
说明:②循环条件为boolean类型表达式,值为false时退出循环;
①初始化部分可以声明多个变量,但变量的类型必须一样,用逗号隔开;
④可以有多个变量更新,用逗号隔开。
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入m");
int m = input.nextInt();
System.out.println("请输入n");
int n = input.nextInt();
int min = (m <= n)? m : n;
for(int i = min;i >= 1;i--){
if(m % i == 0 && n % i == 0){
System.out.println("最大公约数:"+i);
break;
}
}
int max = (n >= m)? n : m;
for(int i = max;i <= m*n;i++){
if(i % m == 0 && i % n == 0){
System.out.println("最小公倍数:"+i);
break;
}
}
}
4.2.while循环
①初始化条件
while(②循环条件){
③循环体;
④迭代条件;
}
①初始化条件;②循环条件;③循环体;④迭代条件。
执行过程:①-②-③-④-②-③-④-...-②
说明:写while循环不要少了迭代条件。否则,循环不能结束,变成死循环;for循环和while循环可以相互转换。
区别:for和while循环的初始化条件部分的作用范围不同。
public static void main(String[] args) {
// 1-100的和
int sum = 0, i = 0;
while (i <= 100) {
sum += i;
i++;
}
System.out.println("sum = " + sum);
// while练习
Scanner input = new Scanner(System.in);
System.out.print("合格了吗?(y/n)");
String anString = input.next();
while (!"y".equals(anString)) {
System.out.println("需要重新开始");
System.out.print("合格了吗?(y/n)");
anString = input.next();
}
System.out.println("完成任务");
}
4.3.do-while循环的使用
①初始化条件
do{
③循环体部分;
④迭代部分;
}while(②循环条件);
①初始化条件;②循环条件;③循环体;④迭代条件
执行过程:①-③-④-②-③-④-...-②
说明:先执行一遍循环操作,在判断循环条件是否满足,满足则继续执行,否则循环结束,注意:循环条件后括号后的分号不可少;开发中,较多使用for和while。
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String anString = "";
do{
System.out.println("你测试了吗");
System.out.print("合格了吗?(y/n)");
anString = input.next();
}while (!"y".equals(anString));
System.out.println("恭喜,你测试通过了");
}
while和do-while循环的区别:执行顺序不同;初始情况不满足循环条件时,while循环一次都不执行,do-while循环不管任何情况都至少执行一次。
for循环和while循环、do-while循环的区别:执行顺序:while循环先判断后执行,do-while循环先执行后判断,for循环先判断在执行。适用情况:循环次数确定的情况,通常选用for循环,循环次数不确定的情况,通常选用do-while循环和while循环
// 增强for循环
// 语法
for(类型 变量名 : 集合){
语句块;
}
// 例如
int[] nums = {43,32,53,54,75};//整型数组
for(int n : nums) {
System.out.println(n);
}
4.4.嵌套循环的使用
将一个循环放在另一个循环体内,构成嵌套循环。for ,while ,do...while均可作为外层循环或内层循环,嵌套循环是把内层循环当成外层循环的循环体。
当内层循环的循环条件为false时,才会跳出内层循环,结束外层的当次循环。内层循环遍历一遍,只相当于外层循环体执行一次;外层循环循环m次,内层循环n次,总共执行了m*n次;外层控制行数,内存控制列数。
public static void main(String[] args) {
// 100以内的素数
for(int i = 2;i <= 100;i++){
for(int j = 2;j < i;j++){
if(i % j == 0){
isFlag = false;
}
}
if(isFlag == true){
System.out.print(i+"\t");
}
isFlag = true;
}
System.out.println();
//获取当前时间距离1970-01-01 00:00:00 的毫秒数
long start = System.currentTimeMillis();
for(int i = 2;i <= 100;i++){
for(int j = 2;j <= Math.sqrt(i);j++){//优化:开方,对本身是指数的自然数
if(i % j == 0){
isFlag = false;
break;//优化:只对本身非直属的自然数
}
}
if(isFlag == true){
System.out.print(i + "\t");
}
isFlag = true;
}
//获取当前时间距离1970-01-01 00:00:00 的毫秒数
long end = System.currentTimeMillis();
System.out.println("花费时间:"+(end - start));
System.out.println("-------------------");
//获取当前时间距离1970-01-01 00:00:00 的毫秒数
long start1 = System.currentTimeMillis();
lebel:for(int i = 2;i <= 100;i++){
for(int j = 2;j <= Math.sqrt(i);j++){//优化:开方,对本身是指数的自然数
if(i % j == 0){
continue lebel;
}
}
System.out.print(i + "\t");
}
//获取当前时间距离1970-01-01 00:00:00 的毫秒数
long end1 = System.currentTimeMillis();
System.out.println("花费时间:"+(end1 - start1));
}
打印图像:外层循环控制行号,内层循环控制每一行的具体实现。请打印一个菱形:
public static void main(String[] args) {
//正立的等腰三⻆形
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 3-i; j++) {//打印空格
System.out.print(" ");
}
for (int j = 0; j < 2* i +1; j++) {//打印
System.out.print("*");
}
System.out.println();
}
//倒立的等腰三⻆形
for (int i = 2; i >=0; i--) {
for (int j = 0; j < 3-i; j++) {//打印空格
System.out.print(" ");
}
for (int j = 0; j < 2* i +1; j++) {//打印
System.out.print("*");
}
System.out.println();
}
}
④打印九九乘法表、杨辉三角和百元百鸡:
// 九九乘法表
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "*" + i + "=" + (i * j) + "\t");
}
System.out.println();
}
}
// 打印杨辉三⻆
public static int num(int x,int y) {
if (y ==1 || y ==x ) {
return 1;
}
int c = num(x-1,y-1) + num(x-1,y);
return c;
}
public static void main(String[] args) {
for (int i = 1; i <= 7; i++) {
for (int j = 0; j < 6-i; j++) {//打印空格
System.out.print(" ");
}
for (int j = 1; j <= i ; j++) {//打印
System.out.print(num(i,j) + " ");
}
System.out.println();
}
}
/*
* 100元买100只鸡,公鸡5元每只,母鸡3元每只,小鸡1元3只
* 有多少方案
*/
public class BaiDemo {
public static void main(String[] args) {
int mj, gj, xj;
for (gj = 0; gj <= 20; gj++) {
for (mj = 0; mj <= 33; mj++) {
for (xj = 0; xj <= 100; xj++) {
if ((gj * 5 + mj * 3 + xj / 3 == 100) && (mj + gj + xj == 100) && (xj % 3 == 0)) {
System.out.println("公鸡" + gj + "只,母鸡" + mj + "只,小鸡" + xj + "只");
}
}
}
}
}
4.5.for和while说明
不在循环条件部分限制次数的结构:for(;;)或while(true)。循环结束方式:1.循环条件部分返回false;2.在循环体中,执行break。
Scanner input = new Scanner(System.in);
int count1 = 0,count2 = 0;
while(true){
int number = input.nextInt();
if(number > 0){
count1++;
}else if(number < 0){
count2++;
}else {
break;
}
}
System.out.println(count1);
System.out.println(count2);
5.特殊流程控制语句
5.1.break和continue
break语句用于终止某个语句块的执行;break语句出现在多层嵌套的语句块中时,可以通过标签指明要终止的是哪一层语句块。
// 结束代码块
{ ......
break;
......
}
// 结束某个循环
label1: { ......
label2: { ......
label3: { ......
break label2;// 结束label2语句块
......
}
}
}
continue只能使用在循环结构中;用于跳过其所在循环语句块的一次执行,继续下一次循环;出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环。
public static void main(String[] args) {
for(int i = 1;i < 10;i++){
if(i % 4 == 0){
// break;//123
continue;//12356789
}
System.out.println(i);
}
System.out.println("-------------");
laber:for(int i = 1;i <= 4;i++){
for(int j = 1;j <= 10;j++){
if(j % 4 == 0){
//break;//默认跳出包裹此关键字最近的一层循环
//break laber;// 输出123,程序结束,结束指定标识的for循环结构
System.out.println();
continue laber;// 输出123123123,结束指定标示的一层循环结构档次循环
}
System.out.print(j);
}
}
}
continue和break的对比,使用场合:break可用于switch结构和循环结构中,continue只能用于循环结构中。作用(循环结构中):break语句终止某个循环,程序跳转到循环块外的下一条语句,continue跳出本次循环,进入下一次循环。
二重循环里的break和continue:在二重循环中,如果break加在了内层循环,只会对内层循环起作用,不会影响外层循环;如果break加在外层循环中,在条件触及时,会终止内外循环;如果continue加在内层循环,只对内层起作用。
5.2.return
return并非专门用于结束循环的,它的功能是结束一个方法;当一个方法执行到一个return语句时,这个方法将被结束。与break和continue不同的是,return直接结束整个方法,不管这个return处于多少层循环之内。
5.3.特殊流程控制语句的说明
名称 | 不同点 | 相同点 |
break | 只能用于switch语句和循环语句,终止本层循环 | break、continue之后不能有其他的语句,因为程序永远不会执行其后的语句。标号语句必须紧接在循环的头部,标号语句不能用在非循环语句的前面。 |
continue | 只能用于循环语句中,只能终止本次循环 |
很多语言都有goto语句,goto语句可随意控制转移到程序中的任意一条语句上,然后执行它。
6.综合练习
需求说明:模拟实现基于文本界面的《家庭记账软件》;该软件能够记录家庭的收入、支出,并能够打印收支明细表;项目采用分级菜单方式。主菜单如下:
假设家庭起始的生活基本金为10000元;每次登记收入(菜单2)后,收入的金额应累加到基本金上,并记录本次收入明细,以便后续的查询;每次登记支出(菜单3)后,支出的金额应从基本金中扣除,并记录本次支出明细,以便后续的查询;查询收支明细( 菜单1)时,将显示所有的收入、支出名细列表;“登记收入”的界面及操作过程如下所示:
“登记支出”的界面及操作过程如下所示:
“收支明细”的界面及操作过程如下所示:
提示:明细表格的对齐,可以简单使用制表符‘\t’来实现;“退 出”的界面及操作过程如下所示:
基本金和收支明细的记录:基本金的记录可以使用int类型的变量来实现:int balance = 10000;收支明细记录可以使用Sting类型的变量来实现,其初始值为明细表的表头。例如:String details = "收支\t账户金额\t收支金额\t说 明\n";在登记收支时,将收支金额与balance相加或相减,收支记录直接串接到details后面即可。
6.1.工具类
package com.shangguigu.project;
import java.util.Scanner;
/**
* Utility工具类: 将不同的功能封装为方法,就是可以直接通过调用方法使用它的功能,而无需考虑具体的功能实现细节。
*/
public class Utility {
private static Scanner scanner = new Scanner(System.in);
/**
* 用于界面菜单的选择。该方法读取键盘,如果用户键入’1’-’4’中的任意字符,则方法返回。返回值为用户键入字符。
*/
public static char readMenuSelection() {
char c;
for (;;) {
String str = readKeyBoard(1);
c = str.charAt(0);
if (c != '1' && c != '2' && c != '3' && c != '4') {
System.out.print("选择错误,请重新输入:");
} else
break;
}
return c;
}
/**
* 用于收入和支出金额的输入。该方法从键盘读取一个不超过4位长度的整数,并将其作为方法的返回值。
*/
public static int readNumber() {
int n;
for (;;) {
String str = readKeyBoard(4);
try {
n = Integer.parseInt(str);
break;
} catch (NumberFormatException e) {
System.out.print("数字输入错误,请重新输入:");
}
}
return n;
}
/**
* 用于收入和支出说明的输入。该方法从键盘读取一个不超过8位长度的字符串,并将其作为方法的返回值。
*/
public static String readString() {
String str = readKeyBoard(8);
return str;
}
/**
* 用于确认选择的输入。该方法从键盘读取‘Y’或’N’,并将其作为方法的返回值。
*/
public static char readConfirmSelection() {
char c;
for (;;) {
String str = readKeyBoard(1).toUpperCase();
c = str.charAt(0);
if (c == 'Y' || c == 'N') {
break;
} else {
System.out.print("选择错误,请重新输入:");
}
}
return c;
}
private static String readKeyBoard(int limit) {
String line = "";
while (scanner.hasNext()) {
line = scanner.nextLine();
if (line.length() < 1 || line.length() > limit) {
System.out.print("输入长度(不大于" + limit + ")错误,请重新输入:");
continue;
}
break;
}
return line;
}
}
6.2.实现类
package com.shangguigu.project;
public class FamilyAccount {
public static void main(String[] args) {
String details = "收支\t账户金额\t收支金额\t说 明\n";
int balance = 10000;
boolean loopFlag = true;
do {
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):");
char key = Utility.readMenuSelection();
System.out.println();
switch (key) {
case '1':
System.out.println("-----------------当前收支明细记录-----------------");
System.out.println(details);
System.out.println("--------------------------------------------------");
break;
case '2':
System.out.print("本次收入金额:");
int amount1 = Utility.readNumber();
System.out.print("本次收入说明:");
String desc1 = Utility.readString();
balance += amount1;
details += "收入\t" + balance + "\t" +
amount1 + "\t" + desc1 + "\n";
System.out.println("---------------------登记完成---------------------");
break;
case '3':
System.out.print("本次支出金额:");
int amount2 = Utility.readNumber();
System.out.print("本次支出说明:");
String desc2 = Utility.readString();
balance -= amount2;
details += "支出\t" + balance + "\t" +
amount2 + "\t" + desc2 + "\n";
System.out.println("---------------------登记完成---------------------");
break;
case '4':
System.out.print("确认是否退出(Y/N):");
char yn = Utility.readConfirmSelection();
if (yn == 'Y') loopFlag = false;
break;
}
} while (loopFlag);
}
}