1、输入和输出
1)输出
在前面的代码中,我们总是使用System.out.println()来向屏幕输出一些内容。
println是print line的缩写,表示输出并换行。因此,如果输出后不想换行,可以用print():
2)格式化输出
Java还提供了格式化输出的功能。为什么要格式化输出?因为计算机表示的数据不一定适合人来阅读:
如果要把数据显示成我们期望的格式,就需要使用格式化输出的功能。格式化输出使用System.out.printf(),通过使用占位符%?,printf()可以把后面的参数格式化成指定格式:
注意,由于%表示占位符,因此,连续两个%%表示一个%字符本身。
占位符本身还可以有更详细的格式化参数。下面的例子把一个整数格式化成十六进制,并用0补足8位:
3)输入
和输出相比,Java的输入就要复杂得多。
我们先看一个从控制台读取一个字符串和一个整数的例子:
解释:
要测试输入,我们不能在线运行它,因为输入必须从命令行读取,因此,需要走编译、执行的流程:
4)练习
请帮小明同学设计一个程序,输入上次考试成绩(int)和本次考试成绩(int),然后输出成绩提高的百分比,保留两位小数位(例如,21.75%)。
public class liushu {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // 创建Scanner对象
System.out.print("Input your last score: "); // 打印提示
float fscore = scanner.nextFloat(); // 读取一行输入并获取字符串
System.out.print("Input your this score: "); // 打印提示
float tscore = scanner.nextFloat(); // 读取2行输入并获取整数
float a=(tscore-fscore)/fscore;
System.out.printf("Hi, you core up%.2f%%\n", a*100); // 格式化输出
}
}
5) 小结
-
Java提供的输出包括:System.out.println() / print() / printf(),其中printf()可以格式化输出;
-
Java提供Scanner对象来方便输入,读取对应的类型可以使用:scanner.nextLine() / nextInt() / nextDouble() / …
2、if判断
1)判断引用类型相等
在Java中,判断值类型的变量是否相等,可以使用 = = 运算符。但是,判断引用类型的变量是否相等,= = 表示“引用是否相等”,或者说,是否指向同一个对象。例如,下面的两个String类型,它们的内容是相同的,但是,分别指向不同的对象,用 = = 判断,结果为false:
要判断引用类型的变量内容是否相等,必须使用equals()方法:
注意:执行语句s1.equals(s2)时,如果变量s1为null,会报NullPointerException:
还可以把一定不是null的对象"hello"放到前面:例如:if (“hello”.equals(s)) { … }。
2)小结
-
if … else可以做条件判断,else是可选的;
-
不推荐省略花括号{};
-
多个if … else串联要特别注意判断顺序;
-
要注意if的边界条件;
-
要注意浮点数判断相等不能直接用==运算符;
-
引用类型判断内容相等要使用equals(),注意避免NullPointerException。
3、switch多重选择
1)switch
除了if语句外,还有一种条件判断,是根据某个表达式的结果,分别去执行不同的分支。
例如,在游戏中,让用户选择选项:
单人模式
多人模式
退出游戏
这时,switch语句就派上用场了。
switch语句根据switch (表达式)计算的结果,跳转到匹配的case结果,然后继续执行后续语句,直到遇到break结束执行。
如果option的值没有匹配到任何case,例如option = 99,那么,switch语句不会执行任何语句。这时,可以给switch语句加一个default,当没有匹配到任何case时,执行default:
使用switch时,注意case语句并没有花括号{},而且,case语句具有“穿透性”,漏写break将导致意想不到的结果:
当option = 2时,将依次输出"Selected 2"、“Selected 3”、“Not selected”,原因是从匹配到case 2开始,后续语句将全部执行,直到遇到break语句。因此,任何时候都不要忘记写break。
如果有几个case语句执行的是同一组语句块,可以这么写:
使用switch语句时,只要保证有break,case的顺序不影响程序逻辑:
switch语句还可以匹配字符串。字符串匹配时,是比较“内容相等”。例如:
switch语句还可以使用枚举类型,枚举类型我们在后面讲解。
2)编译检查
3)switch表达式
使用switch时,如果遗漏了break,就会造成严重的逻辑错误,而且不易在源代码中发现错误。从Java 12开始,switch语句升级为更简洁的表达式语法,使用类似模式匹配(Pattern Matching)的方法,保证只有一种路径会被执行,并且不需要break语句:
注意新语法使用->,如果有多条语句,需要用{}括起来。不要写break语句,因为新语法只会执行匹配的语句,没有穿透效应。
很多时候,我们还可能用switch语句给某个变量赋值。例如:
新语法
4)yield
大多数时候,在switch表达式内部,我们会返回简单的值。
但是,如果需要复杂的语句,我们也可以写很多语句,放到{…}里,然后,用yield返回一个值作为switch语句的返回值:
使用yield返回一个值作为switch语句的返回值
5) 小结
-
switch语句可以做多重选择,然后执行匹配的case语句后续代码;
-
switch的计算结果必须是整型、字符串或枚举类型;
-
注意千万不要漏写break,建议打开fall-through警告;
-
总是写上default,建议打开missing default警告;
-
从Java 14开始,switch语句正式升级为表达式,不再需要break,并且允许使用yield返回值。
4、while循环
注意到while循环是先判断循环条件,再循环,因此,有可能一次循环都不做。
对于循环条件判断,以及自增变量的处理,要特别注意边界条件。
如果循环条件永远满足,那这个循环就变成了死循环。死循环将导致100%的CPU占用,用户会感觉电脑运行缓慢,所以要避免编写死循环代码。
小结
-
while循环先判断循环条件是否满足,再执行循环语句;
-
while循环可能一次都不执行;
-
编写循环时要注意循环条件,并避免死循环。
5、do while循环
小结
-
do while循环先执行循环,再判断条件;
-
do while循环会至少执行一次。
6、for循环
1)for
for循环的功能非常强大,它使用计数器实现循环。for循环会先初始化计数器,然后,在每次循环前检测循环条件,在每次循环后更新计数器。计数器变量通常命名为i。
注意for循环的初始化计数器总是会被执行,并且for循环也可能循环0次。
使用for循环时,千万不要在循环体内修改计数器!在循环体中修改计数器常常导致莫名其妙的逻辑错误。
2)灵活使用for循环
for循环还可以缺少初始化语句、循环条件和每次循环更新语句,例如:
3) for each循环
for循环经常用来遍历数组,因为通过计数器可以根据索引来访问数组的每个元素:
但是,很多时候,我们实际上真正想要访问的是数组每个元素的值。Java还提供了另一种for each循环,它可以更简单地遍历数组:
和for循环相比,for each循环的变量n不再是计数器,而是直接对应到数组的每个元素。for each循环的写法也更简洁。但是,for each循环无法指定遍历顺序,也无法获取数组的索引。
除了数组外,for each循环能够遍历所有“可迭代”的数据类型,包括后面会介绍的List、Map等。
4) 小结
-
for循环通过计数器可以实现复杂循环;
-
for each循环可以直接遍历数组的每个元素;
-
最佳实践:计数器变量定义在for循环内部,循环体内部不修改计数器;
7、break和continue
无论是while循环还是for循环,有两个特别的语句可以使用,就是break语句和continue语句。
1)break
在循环过程中,可以使用break语句跳出当前循环。
因此,break语句通常都是配合if语句使用。要特别注意,break语句总是跳出自己所在的那一层循环。
2)continue
break会跳出当前循环,也就是整个循环都不会执行了。而continue则是提前结束本次循环,直接继续执行下次循环。
在多层嵌套的循环中,continue语句同样是结束本次自己所在的循环。
3)小结
-
break语句可以跳出当前循环;
-
break语句通常配合if,在满足条件时提前结束整个循环;
-
break语句总是跳出最近的一层循环;
-
continue语句可以提前结束本次循环;
-
continue语句通常配合if,在满足条件时提前结束本次循环。