带标签的 break 和 continue (Java)
2002年12月发于 CCW-I
2006年9月搬至 CSDN,略作修改
Java 中有 goto 关键字,但这个关键字没有任何作用,换句话说,我们不能使用 goto 来进行跳转到某行。实际上,结构化程序设计完全不需要 goto 语句即可完成各种流程,而 goto 语句的使用往往会使程序的可读性降低,所以 Java 不允许 goto 跳转。
Java 中同样可以定义标签,使用标识符加冒号 (:) 的形式,如“mylabel:”。不过既然 Java 中的 goto 没有实质性的作用,标签的设计当然就不是为了 goto。
Java 中的标签是为循环设计的,是为了在多重循环中方便的使用 break 和 coutinue 而设计的。正是由于这个原因,Java 的标签只能定义在三种循环 (for() {}, do{} while(), while() {}) 的开始位置,否则编译器会报告说找不到标签。稍后的例子即可更直观的说明。
在循环前面加上标签,就好像给循环起了个名字。而后在循环中使用 break 或者 continue 语句的时候,就可以带上这个标签做为参数,指明跳出 (break) 或者继续 (continue) 哪一个循环,如“break mylabel;”、“continue mylabel;”。现在请看下面的例 1,直观的了解标签的用法,其中的注释已经大略说明了每分部代码在干什么,而示例后面的解释会让你更加明白:
例 1:LabelExmaple.java
/*
* @(#) LabelExample.java
* @author James Fancy
*/
/**
* LabelExample 类将随机生成一个二维数组,
* 数组每一行中的数据都是从小到在的顺序排列,但各行间并没有排序。
* 同时,LabelExample 还会从生成的二维数组里随机找一个数作为要查找的数据。
* 随后在 search 方法中使用带标签的 break 和 continue 语句来优化查找代码。
*/
public class LabelExample {
/**
* 主程序。
*/
public static void main(String[] args) {
LabelExample test = new LabelExample(3, 5);
test.printMatrix();
System.out.println();
test.search();
}
int row; // 二维数组的行数
int col; // 二维数组每行的数据个数
int[][] data; // 数组数据
int lookfor; // 要在数组中查找的数
/**
* 构造函数,生成一个由 row 指定行数,由 col 指定列数的数组。
*/
public LabelExample(int row, int col) {
this.row = row;
this.col = col;
createMatrix();
}
/**
* 打印数组内容。
*/
public void printMatrix() {
System.out.println("row = " + row + ", col = " + col + ", lookfor = "
+ lookfor);
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
System.out.print(" " + data[i][j]);
}
System.out.println();
}
}
/**
* 演示查找过程,使用带标签的 break 和 continue 语句。
*/
public void search() {
//loop1:
// 若在此处定义标签,由于不是其后紧跟循环语句,所以会被勿略掉。
// 被忽略掉的标签,如果在 break 或者 continue 语句中用到,编译时不能通过。
// 如果没有在 break 或者 continue 中用到则编译可以成功。
System.out.println("--- Begin Searching ---");
loop1: for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (data[i][j] > lookfor) {
System.out.println("--- JUMP ---");
continue loop1; // 想想此处用 break,结果会有什么变化
}
if (data[i][j] == lookfor) {
System.out.println("FOUND: data[" + i + "][" + j + "] = "
+ lookfor);
break loop1; // 想想此处用 return,结果会有什么变化
}
System.out
.println("data[" + i + "][" + j + "] = " + data[i][j]);
}
System.out.println("--- LOOP2END ---");
}
System.out.println("--- End Searching ---");
}
/**
* 生成随机数组和随机抽取要查找的数。
*/
private void createMatrix() {
data = new int[row][];
for (int i = 0; i < row; i++) {
data[i] = new int[col];
int t = 0;
for (int j = 0; j < col; j++) {
t += (int) (Math.random() * 20);
data[i][j] = t;
}
}
lookfor = data[(int) (Math.random() * row)][(int) (Math.random() * col)];
}
}这段程序的运行结果如下:
row = 3, col = 5, lookfor = 48
11 21 22 38 39
14 22 40 55 72
11 29 38 48 63
--- Begin Searching ---
data[0][0] = 11
data[0][1] = 21
data[0][2] = 22
data[0][3] = 38
data[0][4] = 39
--- LOOP2END ---
data[1][0] = 14
data[1][1] = 22
data[1][2] = 40
--- JUMP ---
data[2][0] = 11
data[2][1] = 29
data[2][2] = 38
FOUND: data[2][3] = 48
--- End Searching ---
由于程序中所有数据都是随机生成的,所以,运行该程序多次才得到上述较具代表性的结果。
上面程序中,createMatrix 方法和 printMatrix 方法都是工具,一个用于初始化数据,另一个则用于打印数组。而另一个方法 search 则是演示程序的关键之所在。
search 方法中打印的数据足以说明查找的过程。第一个 for 循环 (即标签为 loop1 的那个) 用于遍历二维数组中的所有组 (即每一行);第二个 for 循环嵌套在第一个 for 循环中,用来遍历每一组中的所有数据,以便依次查找。
如果第二个 for 循环对某组数据进行查找的过程中没有找到要查找的数据,则有两种情况:1) 该组的数据全都比要查找的数据小,那么这个循环能够被完整执行,则可以执行该循环之后的语句,即输出“--- LOOP2END ---”。2) 该组数据有比要查找的数据大的数据,那么在检查到第一个比要查找的数据大的数据时,执行了 continue loop1。此语句不仅跳出了第二个 for 循环,还中止了第一个 for 循环中尚未执行的语句,直接进行第一个 for 循环的下一次循环。这里有一个问题,如果把 continue loop1 改成 break 会怎么样呢?如果改了,输入结果就会是:
……
--- JUMP ---
--- LOOP2END ---
……
造成这一现象的原因,是 braek 只中止了第二个循环,却没有中止第一个循环中尚未执行的语句。
现在在来看看找到了目标数据时的情况。如果找到了目标数据,则无论再执行哪一个循环都毫无意义了。所以,要中止掉两个循环。由于是在第二个循环中找到数据的,而第二个循环嵌套在第一个循环当中,如果直接 break 的话,则只能中止第二个循环,第一个循环仍然会继续;而使用 break loop1 则指定了中止第一个循环,既然第一个循环都被中止了,那么依赖于第一个循环的第二个循环当然也就被中止了。这里也有一个问题,为什么不用 return 呢?我想这个问题比上一个问题更好答,因为如果使用 return,那么这两个 for 循环之后的语句怎么办?
需要注意的是,这里的 continue 和 break 都用到了 loop1 标签。如果将代码中“System.out.println("--- Begin Searching ---");”和“loop1:”两条语句的位置交换一下,那么结果会怎么样呢?此时编译器会报告说找不到 loop1 标签。这就是上面提到的,标签定义之后必须紧接着循环语句的原因。不过,如果程序中没有任何一个 break 或者 continue 语句用到 loop1 的话,就无所谓 loop1 定义在哪里了,编译器会把它忽略掉的。
最后,补充一句,一般情况下还是不要使用 label。如果遇到一些比较复杂的多重循环,我更愿意建议使用多个方法来执行每一层的循环,这样会让程序结构显得更加清楚一些。
带标签的 break 和 continue (Java)的更多相关文章
- Java中带标签的break,continue
首先不带标签的break,continue 就不介绍了.大家平时用的最多的也就是这样的情况了. 首先Java中没有goto,但是可以利用带标签的break, continue来实现类似的跳转. 首先来 ...
- Java带标签的break 和带标签的continue
最开始没有学习java 学习的是C语言然后工作开始用java,但当时并没有仔细看过java的书籍,也是大致一翻就看跟C语言很像,了解了基本语法就没有深究了,今天看书开始发现之前没有了解过的语法 带标签 ...
- javascript中标签与break和continue的配合使用
var num = 0; outermost: for (var i=0; i<10; i++) { for (var j=0; j<10; j++) { if (j==5 || i==5 ...
- JavaScript -- 标签 , Break 和 Continue 语句
break 语句用于跳出循环. continue 用于跳过循环中的一个迭代. 标签引用,break 语句可用于跳出任何 JavaScript 代码块. demo: <!DOCTYPE html& ...
- Java中goto和break、continue实现区别
goto 关键字很早就在程序设计语言中出现.事实上,goto 是汇编语言的程序控制结构的始祖:“若条件 A,则跳到这里:否则跳到那里”.若阅读由几乎所有编译器生成的汇编代码,就会发现程序控制里包含了许 ...
- Java基础系列(25)- break、continue、goto
break在任何循环语句的主体部分,均可用break控制循环的流程.break用于强行退出循环,不执行循环中剩余的语句.(break语句也在switch语句中使用) continue语句用于在循环语句 ...
- 9.Break和Continue
Break直接跳出循环和Continue略过本次循环,循环继续执行: Break在任何循坏语句的主体部分,均可用break控制循环的流程.break用于强制退出循环,不执行循环体中的语句,后边语句继续 ...
- [18/11/20]break与continue的区别
一.普通break 和continue 1.break: break用于强行退出循环,不执行循环中剩余的语句. 2.continue continue 语句用在循环语句体中,用于终止某次循环过程,即跳 ...
- java学习之break 和 continue
java当中比较特殊的两个关键字:break,continue.从字面意思来看的话break就是打断的意思,而continue就是继续的意思. 这两个关键词用途范围是很明确的: break:只能用在s ...
随机推荐
- spark优化之并行度
这个其实我前面已经记录过了,这里在记录一下. 我可以通过参数人为的来控制分区大小,增加分区中即可增加任务的并行度,并行度高自然运行的就快了嘛. 官方推荐集群中每个cpu并行的任务是2-3个(也就是2- ...
- 【Java】 大话数据结构(15) 排序算法(2) (快速排序及其优化)
本文根据<大话数据结构>一书,实现了Java版的快速排序. 更多:数据结构与算法合集 基本概念 基本思想:在每轮排序中,选取一个基准元素,其他元素中比基准元素小的排到数列的一边,大的排到数 ...
- H5判断网络状态
1.判断网络连接的网络状态 if (navigator.onLine) { alert('online')} else { alert('offline');} 想要监听浏览器的联网状态, 使用win ...
- python3.5 自带的虚拟环境使用
首先我们要选择一个目录作为虚拟环境的目录, 这里选择c:\myenv cd myenv python -m venv . #在当前目录下创建虚拟环境 创建完成之后,myenv下会多出一些文件 进入sc ...
- 试图(View)
试图是通过命名约定与动作方法想关联的.这个动作方法称为Index,控制器名称为Home; 添加试图,试图名与该试图相关联的动作方法的名称一致.
- [POJ1144]Network
来源:Central Europe 1996 思路:Tarjan求割点. 一个点$x$为割点当且仅当: 1.$x$为根结点且有两棵不相交的子树. 2.$x$不为根结点且它的子树中没有可以返回到$x$的 ...
- MikroTik RouterOS安装后初始化配置(PPPOE拨号上网)
1.修改登入密码 路由器默认登入账号为admin,密码为空,强烈建议修改登入密码保证安全: 2.修改接口名称 选择Interface,切换到Ethernet标签,找到状态是R(run)的两个端口. 给 ...
- bitnami redmine配置全过程
常见问题: 我在自己的机器上面配置完毕以后,移植到另外一台机器上面,登陆页面总是在检查network,并且最后网络加载失败,不论我是用桥接还是NAT方式连接.登陆系统以后,我尝试连接网络失败,尝试执行 ...
- poj2115
构造出模线性方程c * x = b - a mod (2 ^ k) 很容易解. 利用LRJ书上的方法. #include <iostream> using namespace std; # ...
- Docker 传奇之 dotCloud
2010年,几个大胡子年轻人在旧金山成立了一家做 PaaS 平台的公司,起名为「dotCloud」,这个名字让我想起了微软的「DotNet」. dotCloud 主要是基于 PaaS 平台为开发者或开 ...