Java的流程控制语句与C语言中的大同小异,涉及的关键字包括if-else、while、do-while、for、return、break、continue以及选择语句switch。这里只介绍一些Java中相对比较特殊的流程控制语句。
foreach的通用结构是for(对象/变量:数组/容器){…}
以往的for循环必须要使用一个int类型的变量(大多是i、j、k),在数组或者容器时进行计数,但是for each语法简化了这一点:
public class ForEach {
public static void main(String[] args){
int[] numbers = {1,2,3,4};
//这是一般的for循环
for(int i = 0;i < 4;i++){
System.out.println(numbers[i]);
}
//这是for each语法
for(int x:numbers){
System.out.println(x);
}
//结果都为:
//1
//2
//3
//4
}
}
可以看到for each语法通过定义一个变量x,然后将每次访问到的numbers当中的某个元素赋值给这个x。这样通过x可以得到每一个元素。任何一个返回值是一个数组的方法都可以使用foreach结构,比如String里面的toCharArray方法:
for(char x:"hello world".toCharArray()){
System.out.print(x);
}
另外,任何Iterable对象也都可以使用foreach。
当你只想访问数组的一部分时,foreach语法就显得不好用了,更宽泛地说,当你想要获得与数组索引有关的信息时,就难以使用foreach语法,因为语法本身就是忽略掉索引,来简化代码。
比如当你想得到一个数组中值为0的位置的索引时:
int[] array = {1,3,0,2};
for(int i = 0;i < 4;i++){
if(array[i] == 0){
System.out.print(i);
}
}
由于要知道索引i值,因此不能使用foreach语法。
Java中没有goto语句,但是有被限制了的与goto语句具有相似功能的标签用法。
标签与break和continue语句相关,被用于中断循环语句。标签的表示是(标签名:),比如label:
注意,你只能在一个循环语句的之前的那条语句使用标签:
int[] numbers = {1,2};
//标签后面紧接着就是循环语句
label:
for(int i = 0;i < 2;i++){
numbers[i] = 0;
}
//以下代码会报错
label:
int a = 0;//中间不能有别的语句
for(int i = 0;i < 2;i++){
numbers[i] = 0;
}
通过在break和continue后面加上标签,可以完成中断循环,来到标签所在的位置。
其中,break label是直接中止循环,跳到标签所在位置后,不再进入标签所指的这个循环,而是执行接下来的语句。这样,通过使用break label可以直接跳出多重循环。
continue label是中断循环,调到标签所在位置后,从标签所指的循环开始继续原来的循环。与continue不同,continue label是从标签所指的循环继续,而continue是从continue所在的这个循环继续。
下面的代码可以看到break,continue,break label,continue label的示例:
public class Label {
static void test() {
int[] j = {1,2,3};
label1:
for(int k:j){
for(int i = 0;; i++){
if(i == 1) continue label1;
System.out.print(k + " " + i + " ");
}
}
System.out.println();
label2:
for(int k:j){
for(int i = 0;; i++){
if(i == 1) break label2;
System.out.print(k + " " + i + " ");
}
}
System.out.println("成功跳出两层循环");
for(int k:j){
for(int i = 0;; i++){
if(i == 1) break;
System.out.print(k + " " + i + " ");
}
}
System.out.println();
for(int k:j){
for(int i = 0;i < 3; i++){
if(i == 1) continue;
System.out.print(k + " " + i + " ");
}
}
}
public static void main(String[] arg){
Label.test();
}
}
运行的结果为:
可以看到,对于continue label1,在i = 1时直接跳到label1对应的循环语句:for(int k:j)这里,从这里再继续上次的循环,因此,永远只有i为0时值才会被输出;
而对比continue,只是单纯地跳过了i = 1时的输出,在continue所在的这个循环上继续循环,之后的i会被输出。
对于break label2,跳出循环后就不再继续label2所指的这个循环,因此,一个break label语句就可以一次性跳出多重循环。而break只是跳出当前这个循环。
对于break,continue,break label,continue label,它们的区别如下:
1)一般的continue会退回当前循环的开头(顶部),并继续执行。
2)带标签的continue会到达标签的位置,并重新进入紧接在那个标签后面的循环。
3)一般的break会中断并跳出当前循环。
4)带标签的break会中断并跳出标签所指的循环。
switch语句通过将括号中表达式的值与case后面紧跟的值比较,来选择进入哪一个分支(哪一个case),如果没有相符的,就执行default语句(default语句不是必须的,如果没有default语句,也没有符合条件的case分支,那么这个switch语句什么也不会做)。
对于case :冒号后面可以跟一条或多条语句,而且不需要用大括号括起来。
一般情况下,每个case语句最后都会有一个break;来表示直接跳到switch语句的末尾。break也不是必须的,如果没有break,那么会继续执行下一个case甚至default里面的语句(没错,不管下一个case符不符合表达式的值),直到找到一个break为止。
public class UseSwitch {
static void test(){
Random rand = new Random();
int i = rand.nextInt(10);
System.out.println("first switch:");
switch (i){
case 0:System.out.println("i0 = " + i);
case 1:System.out.println("i1 = " + i);
case 2:System.out.println("i2 = " + i);
case 3:System.out.println("i3 = " + i);
case 4:System.out.println("i4 = " + i);
case 5:System.out.println("i5 = " + i);break;
default:System.out.println("In fact,i = "+i);
}
System.out.print("second switch:");
switch (i){
case 0:System.out.print("i0 = " + i);break;
case 1:System.out.print("i1 = " + i);break;
case 2:System.out.print("i2 = " + i);break;
case 3:System.out.print("i3 = " + i);break;
case 4:System.out.print("i4 = " + i);break;
case 5:System.out.print("i5 = " + i);break;
default:System.out.print("In fact,i = "+i);
}
}
public static void main(String[] args){
UseSwitch.test();
}
}
对于第一个switch来说,假如i为0,那么它会不断地执行println,从i0,i1一直到找到break,即i5为止。
而每一个case后面都加了break的第二个switch则不会这样。
对于switch(),括号中的表达式必须能返回一个整数值,即int,char之类的,如果是一个字符串或者浮点数,switch语句不会发挥作用。