Java程序的流程控制语句有:顺序语句、分支语句、循环语句。正常情况下,代码是逐条的按顺序的执行,但是为了能够控制执行满足条件的代码,会加入像if-else分支条件语句、switch多重选择语句、循环语句(如while循环、do-while循环、for循环等)等流程控制语句。
分支语句和循环语句的用法也比较简单,这里着重分析需要注意的一些细节。
if条件语句
if条件语句用到的关键字有:if、else 。
- 在jdk源码里经常可以看到,if条件后只有一条语句时,会省略{},这样是不符合书写规范的,但也是正确的写法,而多条语句时一定要使用{};
- if- else if - else结构的语句在代码中书写过多时显得很臃肿,根据实际情况使用三目运算符,或者工具类替代过多的if条件判断;
- if条件编译是一种Java语法糖,条件编译的实现是根据布尔值的真假,编译器会将不成立的分支消除掉,这一阶段会在编译器解语法糖阶段完成(即编译器会还原最原始的基础语法结构)。举例说明:
// TestIf.java的源码
public class TestIf{
public static void main(String[] args) {
if(true){
System.out.print("1111");
}else{
System.out.print("2222");
}
if(false){
System.out.print("33333");
}else{
System.out.print("444444");
}
}
}
// 经过编译器编译后生成的class文件,TestIf.class
public class TestIf{
public static void main(String[] paramArrayOfString) {
System.out.print("1111");
System.out.print("444444");
}
}
switch多重选择语句
switch多重选择语句用到的关键字有:switch、case、break、default 。
- case子句后无break,会按顺序执行下一个case子句,直到遇到break为止,或者执行到最后的default语句为止;
- break用于循环语句或switch多重选择语句,用于跳出并终止当前循环 或 跳出当前case子句并终止继续往下一个子句执行;
- switch语句的演变历史:case条件在Java5之前仅支持int、byte、short、char等及对应的包装类等类型,Java5时开始支持枚举类型,Java7时开始支持String类型,Java12开始出现预览版(即当前版本会有该功能,后续版本不一定会有,若实现的效果不理想则会在后续版本中被移除)到Java14正式确定为标准版,大致的功能是使用 -> 符号替换掉case子句中的 : 和 break; 。
- 值得注意的是,Java12~Java14还确定了yield关键字的作用,为了避免break跳出子句引发的歧义,用yield返回case子句或default子句的值,举例说明这个已经确定的标准版功能:
// Java12之前的switch语句
public class TestSwitch{
public static void main(String[] args) {
//测试
System.out.println("我喜欢的颜色是:" + selectColor(ColorEnum.BLUE));
}
private static COLOR selectColor(COLOREnum color) {
switch (color) {
case RED:
color = ColorEnum.RED; break;
case YELLOW:
color = ColorEnum.YELLOW; break;
case BLUE:
color = ColorEnum.BLUE; break;
default:
color = ColorEnum.DUCK;
}
return color;
}
}
// Java12之后的预览版和标准版
public class TestSwitch14{
public static void main(String[] args) {
//测试
System.out.println("我喜欢的颜色是:" + selectColor(ColorEnum.BLUE));
}
private static COLOR selectColor(COLOREnum color) {
color = switch (color) {
case RED -> yield ColorEnum.RED;
case YELLOW -> yield ColorEnum.YELLOW;
case BLUE -> yield ColorEnum.BLUE;
default -> color = ColorEnum.DUCK;
};
return color;
}
}
循环语句
循环语句用到的关键字有:do、while、for、break、continue 。
- while循环语句特点是满足while条件才能进入循环,而do-while循环语句特点是无论while条件是否满足都要执行一次do语句块内的语句;
- Java中for循环语句有fori、forr、foreach、迭代器等形式,而foreach循环增强也是一种Java语法糖,编译器编译时是通过迭代器实现循环增强的,举例说明:
// TestFor.java源码
public class TestFor{
public static void main(String[] args) {
List<String> list = Arrays.asList("I", "am", "xxwei", "3");
String name = "";
for (String str : list) {
name += str;
}
System.out.print(name);
}
}
// TestFor.class字节码
public class TestFor{
public static void main(String[] args) {
List<String> list = Arrays.asList("I", "am", "xxwei", "3");
String name = "";
String str;
for(Iterator var3 = list.iterator();var3.hasNext();name = name + str) {
str = (String)var3.next();
}
System.out.print(name);
}
}
- break与continue在循环语句中的区别在于:break 跳出并终止当前循环 ,continue 则是跳出当前循环进入下一次循环;而break与continue 是如何跳出嵌套循环的呢?(使用标记进行跳出循环),最近在看jdk源码,以String类源码中的toLowerCase()方法和lastIndexOf()方法举例:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
// lastIndexOf()方法:从后往前查找给定字符串中,第一个出現的位置
static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount, int fromIndex) {
// 参数检查
int rightIndex = sourceCount - targetCount;
...;
int strLastIndex = targetOffset + targetCount - 1;
char strLastChar = target[strLastIndex];
int min = sourceOffset + targetCount - 1;
int i = min + fromIndex;
// 标记continue跳至的位置
startSearchForLastChar:
while (true) {
while (i >= min && source[i] != strLastChar) {
i--;
}
if (i < min) {
return -1;
}
int j = i - 1;
int start = j - (targetCount - 1);
int k = strLastIndex - 1;
while (j > start) {
if (source[j--] != target[k--]) {
i--;
continue startSearchForLastChar; //跳至标记处,从外层while继续下一次循环
}
}
return start - sourceOffset + 1;
}
}
// toLowerCase():转小写
public String toLowerCase(Locale locale) {
...;
int firstUpper;
final int len = value.length;
// 标记break跳至的位置
scan: {
for (firstUpper = 0 ; firstUpper < len; ) {
char c = value[firstUpper];
if ((c >= Character.MIN_HIGH_SURROGATE)
&& (c <= Character.MAX_HIGH_SURROGATE)) {
int supplChar = codePointAt(firstUpper);
if (supplChar != Character.toLowerCase(supplChar)) {
break scan; //跳至标记处,跳出并终止所有循环
}
firstUpper += Character.charCount(supplChar);
} else {
if (c != Character.toLowerCase(c)) {
break scan; //跳至标记处,,跳出并终止所有循环
}
firstUpper++;
}
}
return this;
}
...;
return new String(result, 0, len + resultOffset);
}
}
总结一下
Java程序流程控制语句需要关注的细节还是挺多的,尤其是普遍的Java语法糖现象(if条件编译、switch支持字符串类型、foreach循环增强等)和Java新版本出现的特性。如今的Java版本迭代周期真的是神速,貌似每半年一个版本,新知识点层出不穷,要求作为技术人需要经常保持学习,让自己跟上技术的发展和变化。
从目前Oracle官方公布的计划表可以看出,Java8和Java11是LTS的(即长期维护的版本),也就是说Java8和Java11已经成为我们必备的技能了。不积硅步无以至千里,点滴付出终将有所收获,共同进步 ~。