Java中的goto

young 397 2021-10-17

java中goto作为关键字,没有实际用处,在C/C++/汇编语言中经常使用,用于跳转至指定位置


虽然Java中的goto不起作用,但Java 中同样可以定义标签(当然Java中标签的设计不是为了goto),使用标识符加冒号的形式,例如retry:


Java 中的标签是为循环设计的,是为了在多重循环中方便的使用 break 和 coutinue 而设计的,这也是Java中唯一用到标签的地方。


正是由于这个原因,Java 的标签只能定义在三种循环 (for() {}, do{} while(), while() {}) 的开始位置,否则编译器会报告说找不到标签。


在循环前面加上标签,就好像给循环起了个名字。而后在循环中使用 break 或者 continue 语句的时候,就可以带上这个标签做为参数,指明跳出 (break) 或者继续 (continue)标签对应的哪个循环,如break retry;continue retry;

public class retryLearn {
    static void retryContinue() {
        System.out.println("执行retryContinue:");
        int i = 0, j = 0;
        retry:
        for (i = 0; i < 2; i++) {
            for (j = 0; j < 5; j++) {
                System.out.println(j);
                if (j == 3) {
                    continue retry;
                }
            }
        }
        System.out.printf("after loop, i = %d, j=%d", i, j);
    }

    static void retryBreak() {
        System.out.println("执行retryBreak:");
        int i = 0, j = 0;
        retry1:
        for (i = 0; i < 2; i++) {
            for (j = 0; j < 5; j++) {
                System.out.println(j);
                if (j == 3) break retry1;
            }

        }
        System.out.printf("after loop, i = %d, j=%d\n", i, j);
    }

    static void whileLabel() {
        System.out.println("执行whileLabel:");
        int i = 0;
        int j = 0;
        whileLabel:
        while (i++ < 10) {
            while (j < 10) {
                System.out.println(j);
                if (j == 6) break whileLabel;
                ++j;
            }
        }
        System.out.printf("after loop, i = %d, j=%d\n", i, j);
    }

    public static void main(String[] args) {
        retryContinue();
        System.out.println("***********************");
        retryBreak();
        System.out.println("***********************");
        whileLabel();
    }
}


以retryBreak函数举例,当第二层for循环中j的值是3的时候,执行break retry1语句,
而retry1这个标签标记的是第一层循环,也就是说对最外层循环执行break,所以当在i的值为0,j的值为3的时候跳转两层嵌套的for循环


源码中的使用:ThreadPoolExecutor#addWorker

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}