【问题标题】:Break label in switch断开开关中的标签
【发布时间】:2023-12-04 17:38:01
【问题描述】:

编辑: 感谢大家的帮助。使用我在前几章中学到的技能和您的建议,我能够让它发挥作用。非常感谢!

我决定尝试通过创建一个简单的文本冒险来巩固我从 Java:初学者指南中学到的东西。我即将开始第 4 章,其中涉及类和方法。前三章讨论了 if、for、while、do-while、switch、简单的键盘交互和 break/continue。

我计划在每一章之后返回并编辑它以使用我学到的新技能。我几乎没有触及表面,我遇到了问题。

// A basic, but hopefully, lengthy text adventure.

class TextAdventure
{
    public static void main(String args[])
    throws java.io.IOException
    {
        System.out.println("\t\t BASIC TEXT ADVENTURE");


        // variables I need, attributes, classes, character name, player's choice, gold
        int str = 0, inte = 0, chr = 0, con = 0, dex = 0, gold;
        char charName, choice;

        System.out.println("Welcome player! You are about to embark upon a quest in the form of a text adventure.");
        System.out.println("You will make choices, fight monsters, and seek treasure. Come back victorious and you");
        System.out.println("could quite possibly buy your way into nobility!");
        System.out.println();


caseChoice: {       
        System.out.println("Please select your class:");
        System.out.println("1. Warrior");
        System.out.println("2. Mage");
        System.out.println("3. Rogue");
        System.out.println("4. Archer");

        choice = (char) System.in.read(); // Get players choice of class



        switch(choice)
        {
        case '1': 
            System.out.println("You have chosen the Warrior class!");
            System.out.println("You're stats are as followed:");
            System.out.println("Str: 16");
            System.out.println("Int: 11");
            System.out.println("Chr: 14");
            System.out.println("Con: 15");
            System.out.println("Dex: 9");
            str = 16; 
            inte = 11;
            chr = 14;
            con = 15;
            dex = 9;
            break;

        case '2':
            System.out.println("You have chosen the Mage class!");
            System.out.println("You're stats are as followed:");
            System.out.println("Str: 16");
            System.out.println("Int: 11");
            System.out.println("Chr: 14");
            System.out.println("Con: 15");
            System.out.println("Dex: 9");
            str = 9; 
            inte = 16;
            chr = 14;
            con = 15;
            dex = 11;
            break;

        case '3':
            System.out.println("You have chosen the Rogue class!");
            System.out.println("You're stats are as followed:");
            System.out.println("Str: 16");
            System.out.println("Int: 11");
            System.out.println("Chr: 14");
            System.out.println("Con: 15");
            System.out.println("Dex: 9");
            str = 15; 
            inte = 11;
            chr = 14;
            con = 9;
            dex = 16;
            break;

        case '4':
            System.out.println("You have chosen the Archer class!");
            System.out.println("You're stats are as followed:");
            System.out.println("Str: 16");
            System.out.println("Int: 11");
            System.out.println("Chr: 14");
            System.out.println("Con: 15");
            System.out.println("Dex: 9");
            str = 9; 
            inte = 11;
            chr = 14;
            con = 15;
            dex = 16;
            break;

            default:
                System.out.println("Not a valid choice, please enter a digit 1-4");
                break caseChoice;

        }

}

    }
}

switch 中默认语句的目的是将代码流带回类选择。我没有收到编译错误或运行时错误。当您选择除 1、2、3 或 4 之外的任何内容时。它说“不是一个有效的选择,请输入一个数字 1-4”,就像它假设的那样,但程序结束了。

我不能在开关中使用这样的标签吗?还是因为它在技术上超出了代码块而不起作用?

【问题讨论】:

  • 不,这不是有效的 java 语法 - 你应该使用 while 循环 (while (!validChoice) { switch () { ... } })

标签: java switch-statement java-8 break


【解决方案1】:

我相信您在问题中描述的是某种 goto 功能,而这不是 Java 中标签的工作方式。

Java 不幸的是支持标签。这在this article from Oracle 中有描述。

所以,基本上你可以有带标签的循环,你可以使用关键字continuebreak等来控制循环的流程。

以下示例说明了如何使用带有break 关键字的循环。当break 被调用时,它会终止带标签的语句,即someLabel 之后的语句。它不会返回到指定标签的位置执行。

someLabel:
    for (i = 0; i < 100; i++) {
        for (j = 0; j < 100; j++) {
            if (i % 20 == 0) {
                break someLabel;
            }
        }
    }

continue 关键字处理标签的方式相同。当你调用例如continue someLabel; 将继续外循环。

作为per this SO-question,你也可以做这样的构造:

BlockSegment:
if (conditionIsTrue) {
    doSomeProcessing ();
    if (resultOfProcessingIsFalse()) break BlockSegment;
    otherwiseDoSomeMoreProcessing();
    // These lines get skipped if the break statement
    // above gets executed
}
// This is where you resume execution after the break
anotherStatement();

所以,基本上如果你 break 到你的 switch 中的标签会发生什么,你会破坏整个语句(而不是跳转到语句的开头)。

您可以通过运行以下程序进一步测试标签。如果您输入“quit”,它会中断 while 循环,否则它只会中断开关。

public static void main(String... args) {
    programLoop:
    {
        while (true) {
            Scanner scanner = new Scanner(System.in);
            final String input = scanner.next();
            switch (input) {
                case "quit":
                    break programLoop; // breaks the while-loop
                default:
                    break; // break the switch
            }
            System.out.println("After the switch");
        }
    }
}

就个人而言,我需要一个非常特殊的情况才能推荐使用标签。我发现如果您重新排列代码以便不需要标签(例如,将复杂代码分解为更小的函数),代码会更容易理解。

【讨论】:

  • 我会更改此内容以阅读更接近“几乎从不推荐使用标签”的内容,因为它们很少是最干净的解决方案,例如,将功能分解为方法的嵌套循环会使事情更难推理。这种情况比较少见,但有时可以处理。
  • @DaveNewton,说得好。我已经把语气软化了一点——谢谢!
  • 一旦我完成第 4 章,我确信我不需要标签声明。现在,我可能只是等待。谢谢你的建议。真的很有帮助。
【解决方案2】:

您可以将代码包含在while 循环中,如下所示:

boolean validChoice=false;
while(!validChoice){
switch(choice){
    case 1:
        //logic
        validChoice=true;
    case 2:
        //logic
        validChoice=true;
    case 3:
        //logic
        validChoice=true;
    default:
        //print "invalid choice" and ask to reenter

}

【讨论】:

    【解决方案3】:

    我认为将标签与break 语句结合使用会使您走错路。您可以简单地在 switch 中使用break 语句,如果您想避免程序退出,只需使用while。在更新的代码下方。

    // A basic, but hopefully, lengthy text adventure.
    
    import java.util.Scanner;
    
    class TextAdventure
    {
        public static void main(String args[])
        {
            System.out.println("\t\t BASIC TEXT ADVENTURE");
    
    
            // variables I need, attributes, classes, character name, player's choice, gold
            int str = 0, inte = 0, chr = 0, con = 0, dex = 0, gold;
            char charName, choice;
    
            System.out.println("Welcome player! You are about to embark upon a quest in the form of a text adventure.");
            System.out.println("You will make choices, fight monsters, and seek treasure. Come back victorious and you");
            System.out.println("could quite possibly buy your way into nobility!");
            System.out.println();
    
            boolean toEnd = false;
            while(!toEnd) {
    
                {
                    System.out.println("Please select your class:");
                    System.out.println("1. Warrior");
                    System.out.println("2. Mage");
                    System.out.println("3. Rogue");
                    System.out.println("4. Archer");
    
                    Scanner scanner = new Scanner(System.in);
                    choice = scanner.next().charAt(0); // Get players choice of class
    
                    toEnd = true;
    
                    switch (choice) {
                        case '1':
                            System.out.println("You have chosen the Warrior class!");
                            System.out.println("You're stats are as followed:");
                            System.out.println("Str: 16");
                            System.out.println("Int: 11");
                            System.out.println("Chr: 14");
                            System.out.println("Con: 15");
                            System.out.println("Dex: 9");
                            str = 16;
                            inte = 11;
                            chr = 14;
                            con = 15;
                            dex = 9;
    
                            break;
    
                        case '2':
                            System.out.println("You have chosen the Mage class!");
                            System.out.println("You're stats are as followed:");
                            System.out.println("Str: 16");
                            System.out.println("Int: 11");
                            System.out.println("Chr: 14");
                            System.out.println("Con: 15");
                            System.out.println("Dex: 9");
                            str = 9;
                            inte = 16;
                            chr = 14;
                            con = 15;
                            dex = 11;
    
                            break;
    
                        case '3':
                            System.out.println("You have chosen the Rogue class!");
                            System.out.println("You're stats are as followed:");
                            System.out.println("Str: 16");
                            System.out.println("Int: 11");
                            System.out.println("Chr: 14");
                            System.out.println("Con: 15");
                            System.out.println("Dex: 9");
                            str = 15;
                            inte = 11;
                            chr = 14;
                            con = 9;
                            dex = 16;
    
                            break;
    
                        case '4':
                            System.out.println("You have chosen the Archer class!");
                            System.out.println("You're stats are as followed:");
                            System.out.println("Str: 16");
                            System.out.println("Int: 11");
                            System.out.println("Chr: 14");
                            System.out.println("Con: 15");
                            System.out.println("Dex: 9");
                            str = 9;
                            inte = 11;
                            chr = 14;
                            con = 15;
                            dex = 16;
    
                            break;
    
                        default:
                            System.out.println("Not a valid choice, please enter a digit 1-4");
                            toEnd = false;
                            break;// caseChoice;
    
                    }
    
                }
            }
    
        }
    }
    

    在 Java 中使用标签是允许的,但不是一个好习惯。再想一想,避免使用像IOException 这样的不必要的异常,因为你的代码不会抛出异常。

    【讨论】:

    • 好吧,我正在关注的这本书总是在他们使用 System.in.read() 时添加 throws java.io.IOException;