您的位置 首页 java

cqh-流程控制语句

6. 流程控制语句

求职,任意,请联系我,能敲电脑就行。

内容导视:

  • 输入与输出
  • 分支控制语句
  • 循环控制语句
  • 转向控制语句

6.1 输入与输出

内容导视:

  • 接收键盘输入
  • 普通输出
  • 格式化输出
  • 输出不同颜色的文字

6.1.1 接收键盘输入

我们需要用到 java .util 包下的 Scanner 类,非 lang 包下的类需要导入,在首行加入 import 完整类名;

  import java.util.Scanner;
 
 public class Hello {
     public  static   void  main(String[] args) {
         // 创建一个 扫描仪 实例,扫描指定输入流产生的值(System.in 流对应于键盘输入)
         Scanner scanner = new Scanner(System.in);
         
         System.out.print("等待你的输入,请按下任意键:");
         
         // 等待输入 字符串 ,使用  String  类型的变量 name 接收
         String name = scanner.next();
         System.out.println("你输入的字符串为:" + name);
         
         System.out.print("等待你输入整数:");
         
         // 等待输入整数,使用 int 类型的变量 num 接收
         int num = scanner.nextInt();
         System.out.println("你输入的整数为:" + num);
         
         /*
             scanner.nextDouble() 是接收小数
             scanner.next().charAt(0) 是接收字符
         */     }
 }  

不想输入,请按 Ctrl + C 结束程序。

注意,让你输入整数时,你却输入了其它类型的字符,会报 java.util.InputMismatch Exception 输入不匹配异常。

可以使用如下方法避免:

  System.out.print("等待输入中:");
 // 如果输入的是整数,此方法会返回 true,执行第一条分支
 if (scanner.hasNextInt()) {
     int num = scanner.nextInt();
     System.out.println("你输入的是个整数:" + num);
 } else {
     System.out.println("你输入的不是整数");
 }  

可以自定义 Readable 的实现类,next 方法内部会调用 getCompleteTokenInBuffer 方法以空格为分隔点读取字符串缓冲区 cb 中的内容,返回的内容称为 token;

当 cb 中无内容或无空格作为分隔点,会调用 read 方法往字符串缓冲区 cb 填充内容,现在字符串缓冲区内容为: 随意内容 随意内容2 随意内容3

再次调用 getCompleteTokenInBuffer 方法,返回 随意内容

如果调用 read 方法时返回了 -1(规定读到末尾返回 -1),cb 不再填充内容,getCompleteTokenInBuffer 会以空格为分隔点读取 cb 中的内容并返回(如果没有空格,直接读取剩余的所有内容),直至无内容可以读取;

这时再调用 next 方法就会抛出 NoSuchElementException 没有更多的元素异常,可以使用 scanner.hasNext 方法判断是否还有内容可以读取;

如果 cb 一直在填充内容,直到 char 数组容量超出 1024 后,报 BufferOverflowException 缓冲区溢出 异常。

  public class TestScanner {
     public static void main(String[] args) {
         Scanner scanner = new Scanner(new MyReadable());
         System.out.println(scanner.next());// 随意内容
         System.out.println(scanner.next());// 随意内容2
         System.out.println(scanner.next());// 随意内容3随意内容
     }
 }
 class MyReadable implements Readable {
     @Override
     public int read(CharBuffer cb) throws IOException {
         StringBuilder builder = new  StringBuilder ("随意内容");
         builder.append(" ");
         builder.append("随意内容2");
         builder.append(" ");
         builder.append("随意内容3");
 
         cb.append(builder);
         return builder.length();// 没有返回 -1,cb 无限填充内容
     }
 }  

System.in 的实际类型为 java.io.Buffered InputStream ,可以使用 InputStreamReader 转换成字符流,将输入存入 char 数组。

  InputStreamReader reader = new InputStreamReader(System.in);
 char[] chars = new char[1024];
 int length = reader.read(chars, 0, 1024);
 System.out.println(new String(chars, 0, length));  

没想到啊, handle 是随机生成的唯一句柄

  /**
  * 调用 read 方法等待键盘输入,将结果存入  bytes  数组中
  */ public static void main(String[] args) throws Exception {
     FileDescriptor fd = new  File Descriptor();
     Field handle = FileDescriptor.class.getDeclaredField("handle");
     handle.setAccessible(true);
     handle.set(fd, getHandle());
 
      FileInputStream  inputStream = new FileInputStream(fd);
      byte [] bytes = new byte[1024];
     System.out.print("请输入:");
     int length = inputStream.read(bytes);
     String result = new String(bytes, 0, length);
     System.out.println(result);
 }
 
 /*
  * 获取 obj 的某个字段值,从 obj 的实际类型开始找,找不到就往上找
  * 一直到 Object 还没有,抛出异常
  */  private  static <T> Object getFieldValue(T obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {
     Class<?> currentClass = obj.getClass();
     while (currentClass != null) {
         try {
             Field field = currentClass.getDeclaredField(fieldName);
             field.setAccessible(true);
             return field.get(obj);
         } catch (NoSuchFieldException e) {
             currentClass = current Class .getSuperclass();
         }
     }
     throw new NoSuchFieldException(fieldName);
 }
 
 private static <T> Object getCurrentClassField(T obj, String fieldName) throws IllegalAccessException, NoSuchFieldException {
     Field field = obj.getClass().getDeclaredField(fieldName);
     field.setAccessible(true);
     return field.get(obj);
 }
 private static <T> T cast(Object o, Class<T> toClass) {
     if (o == null) {
         return null;
     }
     if (toClass.isInstance(o)) {
         return toClass.cast(o);
     }
     throw new ClassCastException(o.getClass() + " cannot be cast to " + toClass);
 }
 private static long getHandle() {
     try {
         // 在 BufferedInputStream 的父类 FilterInputStream 中找到 in 字段
         FileInputStream fileInputStream = (FileInputStream) getFieldValue(System.in, "in");
         FileDescriptor fd = fileInputStream.getFD();
         return (long) getFieldValue(fd, "handle");
     } catch (IOException | NoSuchFieldException | IllegalAccessException e) {
         throw new RuntimeException(e.getMessage(), e);
     }
 }  

6.1.2 普通输出

输出与打印是一个意思,就是使用标准输出流 System .out 在控制台上显示一些文本信息。

System.out.println(“向控制台输出一些内容”);

println 是 print line,即打印并换行:如果接着打印,内容会在下一行显示;如果想下次打印时,文本在同一行,去掉 ln。

6.1.3 格式化输出

就是把数据按指定格式输出,使用 printf 配合占位符 %,先把地方占着,再接收数据填充上去;

由于没有 ln,需要使用 转义字符 n 手动换行, %d 是给整数占位置, %s 是给字符串占位置。占位后,需要传入值,从左至右,顺序不可颠倒,数据类型必须要对应上。

下面是常用的 占位符

占位符

类型

%d

进制 整数

%x

十六进制整数

%o

八进制整数

%f

浮点数

%e

科学计数法表示 浮点数

%s

字符串

%c

字符

%b

布尔 类型

  String ln = "n";
 System.out.println("班级人员详情:");
 String str = "序号:%d,姓名:%s" + ln;        
 
 System.out.printf(str, 101, "张三");
 System.out.printf(str, 102, "猛男");
 System.out.printf(str, 103, "武丑");
 
 System.out.println();
 
 double num = 3.14256;
 double num2 = 100123450.0;
 int num3 = 15;
 System.out.println("数字测试:");
 System.out.printf("这是小数:%f" + ln, num);
 System.out.printf("%f 保留 2 位小数:%.2f" + ln, num, num);
 System.out.printf("%f 的科学计数法显示:%e" + ln, num2, num2);
 System.out.printf("%d 对应的十六进制:%x" + ln, num3, num3);  

printf 方法底层调用 format 方法实现,所以使用 System.out.format()效果也一样。

6.1.4 输出不同颜色的文字

我一般使用两种颜色打印内容,已足够用了。

  System.out.println("正常内容");// 白色
 System.err.println("警告内容");// 红色  

也许你不满足这两种颜色,可以输出以下字符串修改字体样式:

“33[?m”

问号取值如下:(多个 ? 使用 ; 分隔)

  0:原本样式
 1:粗体
 3:斜体
 4:下划线
 7:背景颜色与字体颜色互换
 9:中划线
 21:粗下划线
 51、52:方框
 30 ~ 37:字体颜色分别为黑色、红色、绿色、黄色、蓝色、紫色、蓝绿色、灰色
 40 ~ 47:背景颜色分别为黑色、红色、绿色、黄色、蓝色、紫色、蓝绿色、灰色
 90 ~ 97:字体颜色,同 30 ~ 37,但更深  

大致分为三类:

font Color:字体颜色,在 30 ~ 37 范围内,默认白色

background:背景颜色,在 40 ~ 47 范围内,默认黑色

fontStyle:字体样式:1、3、4、9

假如我现在想要输出带中划线的红色粗斜体,选用 9、31、1、3 这 4 种:(顺序不分先后)

 System.out.print("33[9;31;1;3m");
System.out.println("指定样式的字体");
System.out.println("指定样式的字体2");  

想要恢复为原本样式,输出如下字符串:

 System.out.print("33[0m");
System.out.println("原本样式");  

可以配合占位符使用:

 // 格式化输出字符串
public static void printf(String str, int fontColor, int background, int fontStyle) {
    // 前半部分使用占位符,指定输出字体的样式,后半部分 33[0m 还原样式,n 换行
    System.out.printf("33[%d;%d;%dm%s33[0mn", fontColor, background, fontStyle, str);
}
// 返回格式化的字符串
public static String getColorString(String str, int fontColor, int background, int fontStyle) {
    return String.format("33[%d;%d;%dm%s33[0m", fontColor, background, fontStyle, str);
}

// 输出的字符串为蓝色
public static void printlnBlueFont(String str) {
    System.out.println(getColorString(str, 34, 2, 2));
}
// 输出的字符串为紫色
public static void printlnPurpleFont(String str) {
    printf(str, 35, 2, 2);
}  
 public static void main(String[] args) {
    printlnBlueFont("Hello World!");
    printlnPurpleFont("Hello World!");
    
// 输出蓝色背景、带下划线的红色字体
    printf("Hello World!", 31, 44, 4);
}  

6.2 分支 控制语句

内容导视:

  • if else
  • switch case

分支控制语句也称选择语句。

程序一般自上而下,逐行执行,但是有时也需要特殊操作;比如根据条件选择性地执行某段代码、循环执行某段代码…

6.2.1 if else

if else 语句最多只会执行一条分支,类似走路遇见岔路,只能选一条通过。先从最简单的 if 讲起。

单条分支

语法:

 if (布尔类型的值) {
    java 语句...
}  

当布尔类型的值为 true 时,才会执行 {} 中的 java 语句,如下:

 int age1 = 11;
int age2 = 8;
if (age1 > age2) {
    System.out.println("我比你大");// 此句话会输出
}  

当 {} 中只有一条语句时,可以省略 {};但是最好不要那么做,以免别人误解。

 if (age1 > age2) System.out.println("我比你大");  

if else

语法:

 if (布尔类型的值) {
    分支一...
} else {
    分支二...
}  

布尔类型的值为 true,执行第一条分支;为 false,执行第二条分支。

 char sex = '1';

if (sex == '0') {
    System.out.println("输出女");
} else {
    System.out.println("输出男");// 此句会输出
}  

多条分支

语法:

 if (值1) {
    分支一...
} else if (值2) {
    分支二...
} else if (值3) {
    分支三...
} ...  

从上至下,只执行第一个值为 true 的分支;else if 可以无限追加。

 double scope = 100.0;

if (scope < 60) {
    System.out.println("你的成绩不及格");
} else if (scope < 80) {
    System.out.println("你的成绩一般");
} else if (scope < 90) {
    System.out.println("你的成绩良好");
} else if (scope < 100) {
    System.out.println("你的成绩优秀");
}  

上面的分支都不会执行,因为从上至下,没有布尔表达式为 true 的。

 int age = 20;
if (age < 18) {
    System.out.println("未成年人");
} else if (age < 35) {
    System.out.println("青年人"); // 此句将会输出
} else if (age < 50) {
    System.out.println("中年人");
}  

执行第二条分支。

if else if … else

语法:

 if (值1) {
    分支一...
} else if (值2) {
    分支二...
} else if (值3) {
    分支三...
} ...
} else {
    最后的分支
}      

当所有分支括号里的值都为 false 时,执行最后的分支。

 int age = 888;
if (age < 18) {
    System.out.println("未成年人");
} else if (age < 35) {
    System.out.println("青年人"); // 此句将会输出
} else if (age < 50) {
    System.out.println("中年人");
} else if (age < 200) {
    System.out.println("老年人");
} else {
    System.out.println("妖怪吧!");// 由于上面分支都不满足,执行此条分支
}  

嵌套分支

if 语句中有 if 语句。

 double scope = 120;

if (scope >= 0 && scope <= 100) {
    // 语句块 1
    if (scope < 60) {
   System.out.println("你的成绩不及格");
} else if (scope < 80) {
    System.out.println("你的成绩一般");
} else if (scope < 90) {
   System.out.println("你的成绩良好");
} else {
    System.out.println("你的成绩优秀");
}
    
} else {
    // 语句块 2
    System.out.println("这是人能考出的成绩?");
}
/*
只有分数在 [0 ~ 100] 之间才会执行语句块 1,否则执行语句块 2
*/  

嵌套最好不要超过三层,否则人容易迷惑,可读性太差。(可以使用 if else)

if else 不是新的关键字,而是嵌套的简单写法,因为当 if 或 else 中只包含一条 java 语句时,大括号可以省略。(建议不要省略)

 if (true)
    System.out.println("好");
else
    System.out.println("差");  

例:

 int scope = 50;
if (scope < 60) {
    System.out.println("差");
} else if (scope < 80) {
    System.out.println("良");
} else if (scope <= 100) {
    System.out.println("优");
}  

把被省略的大括号加上:

 int scope = 50;
if (scope < 60) {
    System.out.println("差");
} else {
    if (scope < 80) {
        System.out.println("良");
    } else {
        if (scope <= 100) {
            System.out.println("优");
        }
    }
}  

6.2.2 switch case

语法:

 switch (值) {
case 字面量1:
语句块1;
break;

case 字面量2:
    语句块2;
    break;
    
    case 字面量3:
    语句块3;
    break;
    ...
    default:
    语句块4;
}  

从上至下,执行字面量等于 switch 括号中的值的 case 分支语句,遇见 break 跳转至 switch 主体的末尾,然后结束 switch 语句。

default 如同 else 一样,可以不写;当没有一个匹配上时,就执行此分支的语句。

 char key = 's';

switch (key) {
    case 'w' :
        System.out.println("上");
        break;
    case 's' :
        System.out.println("下");// 此条将会被输出
        break;   
    case 'a' :
        System.out.println("左");
        break;  
    case 'd' :
        System.out.println("右");
        break;  
    default:
        System.out.println("其它");
}  

注意

  1. case 后的字面量对应的数据类型必须与 switch 括号中的值的类型一致,或者可以自动转成此类型。
  2. case 后的字面量值不能重复。
  3. switch 括号中的值的数据类型只能是 int、String、Enum。(能够自动转换为这三种类型的也算)
  4. case 后的值不能是变量,只能是字面量与常量。

JDK7 之前只能是 int。

case 穿透现象

当执行某条 case 分支的语句时,如果没有 break 语句结尾,直接顺序执行之下的所有 case、default 分支的语句;只有执行了 break 语句,才会退出 switch 语句。

看清楚了,我把每条分支的 break 都略去了。

 String weather = "sunny";

switch (weather) {
    case "cloudy" :
        System.out.println("阴天");
    case "sunny" :
        System.out.println("晴天");
    case "rain" :
        System.out.println("雨天");
    default:
        System.out.println("其它天气");
}  

当输出 “晴天” 时,由于没有遇到 break 语句,继续执行之下语句,输出 “雨天”、“其它天气”。

打个比方吧:

在一个神奇的小区,房子一排排却单向连通,一旦进入其中一家,便可以由内部通道去往下一家。有的住户觉得很不安全,偷偷做了防范措施。

一个小偷捡到了一把锁,尝试着用它开启一户户门,从巷头走到巷尾。诶,有一扇门开了,进去拿了东西,但是主人安了警报铃,小偷马上 GG 了。另一个小偷也来了,也打开扇门,恰好主人家忽视了防护,小偷偷完这家后,直接顺着通道前往下一家,居然都没防范措施,直接全部偷完。

case 合并

如果多个 case 分支执行的是相同的语句,可以将其合并:

 char sex = '男';
switch (sex) {
    case '0' : case '女' :
        System.out.println("我有四个蛋");
        break;
    case '1' : case '男' :
        System.out.println("咖喱?什么咖喱?");
        System.out.println("快还给我!这是我的!");
        break;
    default:
        System.out.println("只想守护你");
}  

当 sex 等于 ‘0’ 或 ‘女’ 时,执行第一条分支;sex 等于 ‘1’ 或 ‘男’ 执行第二条分支;都不满足执行默认分支。

这不是新语法,只是 case ‘0’ 分支中没有语句,包括 break 语句;当 sex = ‘0’ 时,会出现 case 穿透现象,接着执行下个 case 分支中的语句,也就是 case ‘女’,直到遇见 break 退出 switch 语句。

 switch (sex) {
    case '0' : 
    case '女' :
        System.out.println("我有四个蛋");
        break;
    case '1' :
    case '男' :
       ...
}  

default

同理,default 分支不一定非要在最后一条,也可以与第一条的 case 语句合并,都不匹配时,case 穿透,执行第一条分支。

如下例,都不满足,应执行 default 中的语句,由于 default 中没有 break 语句,接着执行 case 0 分支,输出 0 ,遇到 break,结束 switch 语句。

 switch(3) {
    default:
    case 0:
        System.out.println("0");
        break;
    case 1:
        System.out.println("1");
        break;
    case 3:
        System.out.println("2");
        break;  
}  

6.3 循环控制语句

内容导视:

  • for
  • while

有些时候,我们需要重复执行某些事情…

6.3.1 for

语法:

 for (初始化表达式; 布尔值(循环条件); 更新表达式) {
    循环体中的语句
}  

执行顺序:

先执行初始化表达式,如果循环条件为 true,则执行循环体中的语句;

执行完后,执行更新表达式,如果循环条件为 true,则执行循环体中的语句…

直到循环条件为 false,退出 for 语句。

示例:

 for (int i = 0; i < 2; i++) {
    System.out.println("两指夫人" + i);
}  

分析:

 i --> 0;
此时 i 小于 2,为 true,执行循环体中的语句,输出:两指夫人0

执行更新表达式 i++
i --> 1;
此时 i 小于 2,为 true,执行循环体中的语句,输出:两指夫人1

执行更新表达式 i++
i --> 2;
此时 i 小于 2 为 false,退出循环  

小技巧:

1)由于定义在 for () 中的变量的作用域仅在 for 循环体内:

 for (int i = 0; i < 2; i++) {}
System.out.println(i);  
 Hello.java:8: 错误: 找不到符号
System.out.println(i);  

为了能够在其它地方能够访问到此变量,可以将其提取出来。

 int i = 0;
for (; i < 2; i++) {}
System.out.println(i);  

2)初始化语句与更新表达式可以有多个,使用 , 隔开,但是要求变量的类型相同。

 for (int i = 1, j = 2; i < 4 && j < 6; i++, j += 2) {
    System.out.println("i:" + i 
+ ",j:" + j);
}  

分析:

 i --> 1,j --> 2
i < 4 && j < 6 为 true,执行循环体,输出:i:1,j:2

执行更新表达式:i++、j += 2
i --> 2,j --> 4
i < 4 && j < 6 为 true,执行循环体,输出:i:2,j:4

执行更新表达式:i++、j += 2
i --> 3,j --> 6
i < 4 && j < 6 为 false,结束 for 循环  

6.3.2 while

语法:

 while (布尔值(循环条件)) {
    循环体中的语句
}  

如果布尔值为 true,执行循环体;执行结束后再判断布尔值…直到布尔值为 false,退出循环。

示例:

 int i = 0;
while (i < 3) {
    System.out.println(i);
    i++;
}  

输出 0、1、2;因为当 i = 3 时,i < 3 为 false,退出循环。

do while

语法:

 do {
    循环体中的语句
} while (布尔值);  

先执行循环体,执行结束后判断布尔值,如果为 true,执行循环体,再判断布尔值…直到布尔值为 false,退出循环。

与 while 不同的是,do while 是先执行再判断,所以一定会执行一次。

示例:

 int i = 0;
do {
    System.out.println(i);
    i++;
} while (i < 3);  

输出 0、1、2。

嵌套循环

以 for 循环为例。之前先讲过嵌套,你就理解为套娃就行了,看到阿衰他妈给阿衰做了一笼包子,结果大脸妹打开包子一看,包子里有多个小包子,继续打开,更小的包子…无穷尽也,很影响食欲。嵌套最好不要超过三层,第一怕人发昏,第二是效率低。

 for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        System.out.println(j);
}
}  

分析:

 当 i = 0 时,执行循环体输出 0、1、2,当 j = 3 时,不满足条件,结束内层 for 循环
当 i = 1 时,执行循环体输出 0、1、2...
当 i = 2 时,执行循环体输出 0、1、2...

当 i = 3 时,不满足循环条件,退出外层 for 循环  

外层的 for 一共循环执行 3 次;每次外层循环时,内层的 for 会循环执行 3 次;也就是内层的循环体中的语句一共执行 3 * 3 = 9 次。

6.4 转向控制语句

内容导视:

  • break
  • continue
  • return

终止或跳过循环…

6.4.1 break

break 代表终止语句块的执行(不再执行),一般用于 switch case、for、while 中。

举例:当 i = 2 时,终止循环。

 int i = 0;
while (i < 10) {
    if (i == 2) {
        System.out.println("终止了循环");
        break;
    }
    System.out.println(i);
    i++;
}  

输出 0、1;当 i 等于 2 时,执行 if 语句,输出 “终止了循环”,接着执行 break 终止 for 循环。

当 break 用在嵌套循环中,默认终止最近的循环体。

 for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 2; j++) {
        if (j == 1) {
            break;
        }
        System.out.println(j);
    }
}  

分析:

 当 i = 0 时,输出 0
当 i = 1 时,输出 0
当 i = 2 时,输出 0
因为当 j = 1 时,满足了 if 条件,执行了 break,终止了里层的 for 循环。
(只是代表里层的循环执行结束,但外层循环还在继续执行)
当 i = 3 时,不满足条件,退出外层循环。  

也可以自定义标签,终止标签对应的循环。

 key1: for (int i = 0; i < 3; i++) {
    key2: for (int j = 0; j < 2; j++) {
        if (j == 1) {          
            break key1;
        }
        System.out.println(j);
    }
}  

输出 0;当 j = 1 时,执行了 break,终止 key1 对应的 for 语句。

6.4.2 continue

跳过本次循环。(提前结束本次循环,开始下一次循环)

 int i = 0;
while (i < 6){
    i++;
    if (i == 3){
        continue;
    }
    System.out.println(i);

}  

当 i = 3 时,执行了 continue,跳过本次循环,没有执行剩下的代码,直接进入下一次循环。所以输出 1、2、4、5、6。

需要注意的是,此时我把 “i++” 放在了前面;因为 i++ 如果在 continue 后,当 i = 3 时,跳过本次循环,没有执行 i++,下次循环 i 还是 3,一直跳过,无限循环,永远执行不到 i++。

6.4.3 return

当方法没有返回值(void)时,使用 return; 代表结束当前方法的执行。(结束当前方法意味着其它语句不再执行;在 main 方法中使用代表结束程序)

 public static void main(String[] args) {
    // for
    for (int i = 0; i < 6; i++) {
        System.out.println(i);
        if(i == 4) {
            return;// 同一个域中,此语句必须放到结尾处,因为之后的语句执行不到,没有意义
        }
}
    // 其它语句
System.out.println("代码块");
}  

输出 0、1、2、3、4 后,当 i = 4 时,执行 if 语句中的 return,结束 main 方法的执行。

如果把 return 换成 break,只结束了 for 循环,接着还会输出 “代码块”。

return 以后讲方法返回值时还会用到,现在只需了解它能够终止方法执行即可。

6.x 总结回顾

switch case 语句注意 break 不可省略,以免出现 case 穿透现象。

for 与 while 循环注意控制循环结束条件,防止循环条件一直为 true,避免无限循环。

6.y 课后习题

6.1 打印 [n,m] 之间的所有是 x 倍数的整数,统计个数及总和。

6.2 输出 1 + (n – 1)= n、2 + (n – 2)= n、…、50 + (n – 50)= n。

6.3 打印九九乘法口诀表。

6.4 打印一个 n 层的空心金字塔。例:当 n = 5 时,输出如下:

     *
   * *
  *   *
 *     *
*********  

6.5 找出 3 位数的水仙花数,水仙花数是各位数的三次方之和等于此数,比如 153 = 13 + 53 + 33 = 153。

6.6 计算 1 – 1/2 + 1/3 – 1/4 + … – 1/100。

6.7 计算 1 + (1 + 2)+ (1 + 2 + 3)+ … + (1 + 2 + 3 + 4 + … + 100)。

6.z 习题答案

6.1 打印 [n,m] 之间的所有是 x 倍数的整数,统计个数及总和。

先考虑输出 [1,50] 之间所有是 5 的倍数:

 // (1)输出 1 ~ 50
for (int i = 1; i <= 50; i++) {
    System.out.println(i);
}  
 // (2)只有当 i 是 5 的倍数时,才输出
for (int i = 1; i <= 50; i++) {
    if (i % 5 == 0) {
    System.out.println(i);
    }
}  
 // (3)定义变量保存统计个数、和
int count = 0;
int sum = 0;
for (int i = 1; i <= 50; i++) {
    if (i % 5 == 0) {
        count++;
    sum += i;
    }
}
System.out.println("总和:" + sum);
System.out.println("是 5 的倍数的数的个数:" + count);  
 // (4)扩展到一般情况
// 这里可以考虑接收键盘输入,得到整数值
int n = 1;
int m = 50;
int x = 5;

int count = 0;
int sum = 0;
for (int i = n; i <= m; i++) {
    if (i % x == 0) {
        count++;
    sum += i;
    }
}
System.out.println("总和:" + sum);
System.out.println("是 " + x + " 的倍数的数的个数:" + count);  

6.2 输出 1 + (n – 1)= n、2 + (n – 2)= n、…、50 + (n – 50)= n。

观察变的部分,1 ~ 50,将其提取出来,定义为 i:

 for (int i = 1; i <= 50; i++) {
    System.out.println(i + " + (n - " + i + ") = n");
}  

6.3 打印九九乘法口诀表。

效果如图:

由于我们是按行输出的,所以观察递增的部分:1 ~ 9;也就是乘号右边。

 for (int i = 1; i <= 9; i++) {
    System.out.println(i);
}  

观察乘号左边与 i 的关系

 当 i = 1 时,输出 1
i = 2 时,输出 1、2
i = 3 时,输出 1、2、3
...
i = 8 时,输出 1、2、3、4、5、6、8
i = 9 时,输出1、2、3、4、5、6、8、9

可以发现输出的开始都是 1,结束都是 i
定义一个变量 j,使用 for 循环输出这些值  
 for (int i = 1; i <= 9; i++) {
    System.out.print(i + "t");
    for (int j = 1; j <= i; j++) {
        System.out.print(j + " ");
    }
    System.out.println();
}  

开始组合 “j * i = 某值” 字符串:

 for (int i = 1; i <= 9; i++) { 
    for (int j = 1; j <= i; j++) {
        System.out.print(j + "x" + i 
+ "=" + (i * j) + "t");
    }
    System.out.println();
}  

注意同行显示的乘法口诀,别用 ln 换行了;应该输出完这行所有的乘法口诀后,再换行。

6.4 打印一个 n 层的空心金字塔。例:当 n = 5 时,输出如下:

     *
   * *
  *   *
 *     *
*********  

简化 1:打印实心金字塔

     *
   ***
  *****
 *******
*********  

简化 2:将星号前面空格去掉

 *
***
*****
*******
*********

第 2 层是 1+2 = 2*2 - 1
第 3 层是 1+2+2 = 2*3 - 1
第 4 层是 1+2+2+2 = 2*4 - 1  

通过观察,发现每层都比上层多 2 个星号,通过归纳得出第 i 层为 2 * i – 1 个星号。

先打印 5 层。i 控制层数 1 ~ 5 层;j 控制每层的星号数,一共输出 2 * i – 1 个星号。

 for (int i = 1; i <= 5; i++) {
    for (int j = 1; j <= 2 * i - 1; j++) {
        System.out.print("*");
    }
    System.out.println();
}  

接下来观察简化 1:

 第 1 行前面有 4 个空格
第 2 行前面有 3 个空格
第 3 行前面有 2 个空格
第 4 行前面有 1 个空格
第 5 行前面有 0 个空格
所以当第 i 行前面应该打印 5 - i 个空格后再打印 *  
 for (int i = 1; i <= 5; i++) {
    for (int z = 1; z <= 5 - i; z++) {
        System.out.print(" ");
    }
    for (int j = 1; j <= 2 * i - 1; j++) {
        System.out.print("*");
    }
    System.out.println();
}  

接下来观察最初的空心版本,除了最后一层,其它层除了开始的和结束的星号,都输出空格:

 for (int i = 1; i <= 5; i++) {
    for (int z = 1; z <= 5 - i; z++) {
        System.out.print(" ");
    }
    for (int j = 1; j <= 2 * i - 1; j++) {
        // 不是最后一层,除了开始与结束输出星号,其它都输出空格
        if (i != 5) {
            if (j == 1 || j == 2 * i - 1) {
                System.out.print("*");   
            } else {
                System.out.print(" ");   
            }
        } else {
            System.out.print("*");
        }
    }
    System.out.println();
}  

最后将 5 改为 n:

 int n = 10;
for (int i = 1; i <= n; i++) {
    for (int z = 1; z <= n - i; z++) {
        System.out.print(" ");
    }
    for (int j = 1; j <= 2 * i - 1; j++) {
        if (i != n) {
            if (j == 1 || j == 2 * i - 1) {
                System.out.print("*");   
            } else {
                System.out.print(" ");   
            }
        } else {
            System.out.print("*");
        }
    }
    System.out.println();
}  

6.5 找出 3 位数的水仙花数,水仙花数是各位数的三次方之和等于此数,比如 153 = 13 + 53 + 33 = 153。

首先需要得到各位上的数:

 设一个三位数的整数 i,把百位、十位、个位上的数得到
百位 = i / 100
十位 = i % 100 / 10
或
十位 = i / 10 % 10
个位 = i % 10  

那么从 100 ~ 999 范围内查找,当满足水仙花就输出:

 for (int i = 100; i < 1000; i++) {
    int h = i / 100;
    int t = i % 100 /10;
    int u = i % 10;
    // 可用 Math 的 pow 方法求幂
    if (i == h * h * h + t * t * t + u * u * u) {
        System.out.println(i);
    }
}  

扩充内容:

得到四位数上的各位数,以 1234 为例

 千 1234 / 1000    
百 1234 % 1000 / 100 或 1234 / 100 % 10
十 1234 % 100 / 10 或 1234 / 10 % 10
个 1234 % 10  

6.6 计算 1 – 1/2 + 1/3 – 1/4 + … – 1/100。

观察规律:

分子都为 1,分母以 1 递增到 100;设为 i,当 i 为偶数时,符号为负。

 double sum = 0;
for (int i = 1; i <= 100; i++) {
    if (i % 2 == 0) {
        sum += -1.0 / i;
    } else {
        sum += 1.0 / i;
    }
    /*
    double num = i % 2 == 0 ? -1.0 / i : 1.0 / i;
    sum += num;
    */}
System.out.println(sum);// 0.688172179310195  

分子的 1 必须写成小数,否则除了第一项其它式子的结果都为 0;sum 必须为 double 类型,如果为 int 类型,+= 会被强转为整数,恰巧结果小于 1,统统转成 0。

6.7 计算 1 + (1 + 2)+ (1 + 2 + 3)+ … + (1 + 2 + 3 + 4 + … + 100)。

方法 1:

 一共有 100 个式子相加
第 1 个式子是 1
第 2 个式子是 1+2
第 3 个式子是 1+2+3

得出规律,当 i > 1 时
第 i 个式子是从 1 加到 i,想办法把 1 到 i 这几个数弄到手,累加

定义 i 控制式子的个数,从 1 到 100
定义 j 控制每个式子,从 1 加到 i  
 int sum = 0;
for (int i = 1; i <= 100; i++) {
    for (int j = 1; j <= i; j++) {
        sum += j;
    }
}
System.out.println(sum);// 171700  

方法 2:

  第 1 个式子是 1 = 1
 第 2 个式子是 1+2 = 3
 第 3 个式子是 1+2+3 = 6
 
 得出规律,当 i > 1 时
 第 i 个式子是第 i-1 个式子的结果 + i
 
 i 从 1 到 100
 考虑使用 formula 记录第 1 个式子的和,然后不停地累加 i。
 第一次循环,formula = 1
 第二次循环,formula + i = 1 + 2 = 3
 第三次循环,formula + i = 3 + 3 = 6
 ...
 每个式子的和得到了,再定义 sum 变量将这些式子的和累加,即 sum += formula
 同时为了和谐,修正 formula = 0;第一次循环 formula + i = 0 + 1 = 1  
  int formula = 0;
 int sum = 0;
 for (int i = 1; i <= 100; i++) {
     formula += i;
     sum += formula;
 }
 System.out.println(sum);  

方法 3:

  观察式子
 发现 1 出现了 100 次,2 出现了 98 次...100 出现了 1 次
 所以总和为 1 * 100 + 2 * 99 + ... + 100 * 1  
  int sum = 0;
 for (int i = 1; i <= 100; i++) {
     sum += i * (101 - i);
 }
 System.out.println(sum);  

扩展为一般情况:

  int n = 100;
 int sum = 0;
 for (int i = 1; i <= n; i++) {
     sum += i * (n + 1 - i);
 }
 System.out.println(sum);  

文章来源:智云一二三科技

文章标题:cqh-流程控制语句

文章地址:https://www.zhihuclub.com/200547.shtml

关于作者: 智云科技

热门文章

网站地图