什么是 switch 表达式,它们与 switch 语句有何不同?

What are switch expressions and how are they different from switch statements?

作为 Java SE 12 的一部分,switch expressions 被引入,并且自 Java SE 14 以来,它们已被标准化。它们与 switch 语句有何不同?

switch语句:

if/else if/else 语句不同,switch 语句可以有多个可能的执行路径。 switch 适用于基本类型 byteshortcharint,它们各自的包装类型(ByteShortCharacterInteger),枚举类型,以及 String 类型 1if-else 语句用于根据值或条件的范围测试表达式,而 switch 语句用于仅基于单个值测试表达式。

演示

enum PaymentStatus {
    UNPAID, PARTPAID, PAID, DISPUTED, UNKNOWN;
}

public class Main {
    public static void main(String[] args) {
        String message = "";
        PaymentStatus paymentStatus = PaymentStatus.PARTPAID;

        switch (paymentStatus) {
        case UNPAID:
            message = "The order has not been paid yet. Please make the minimum/full amount to procced.";
            break;
        case PARTPAID:
            message = "The order is partially paid. Some features will not be available. Please check the brochure for details.";
            break;
        case PAID:
            message = "The order is fully paid. Please choose the desired items from the menu.";
            break;
        default:
            throw new IllegalStateException("Invalid payment status: " + paymentStatus);
        }
        System.out.println(message);
    }
}

输出:

The order is partially paid. Some features will not be available. Please check the brochure for details.

switch表达式:

switch 表达式是在 Java SE 12 中引入的。但是,它在 Java SE 12 中仍然作为 Preview 功能,并且13 并最终使用 Java SE 14 进行了标准化。Like any expressionswitch 表达式计算为单个值,并且可以在语句中使用。它还引入了“arrow case”标签,不再需要 break 语句来防止掉线。从 Java SE 15 开始,支持的数据类型没有变化(在上面的 switch 语句部分提到)。

演示

enum PaymentStatus {
    UNPAID, PARTPAID, PAID, DISPUTED, UNKNOWN;
}

public class Main {
    public static void main(String[] args) {
        PaymentStatus paymentStatus = PaymentStatus.PARTPAID;

        String message = switch (paymentStatus) {
        case UNPAID -> "The order has not been paid yet. Please make the minimum/full amount to procced.";
        case PARTPAID -> "The order is partially paid. Some features will not be available. Please check the brochure for details.";
        case PAID -> "The order is fully paid. Please choose the desired items from the menu.";
        default -> throw new IllegalStateException("Invalid payment status: " + paymentStatus);
        };

        System.out.println(message);
    }
}

输出:

The order is partially paid. Some features will not be available. Please check the brochure for details.

switch表达式与yield:

自 Java SE 13 起,您可以使用 yield 语句而不是箭头运算符 (->) 来 return 来自 switch 表达式的值.

演示

enum PaymentStatus {
    UNPAID, PARTPAID, PAID, DISPUTED, UNKNOWN;
}

public class Main {
    public static void main(String[] args) {
        PaymentStatus paymentStatus = PaymentStatus.PARTPAID;

        String message = switch (paymentStatus) {
        case UNPAID:
            yield "The order has not been paid yet. Please make the minimum/full amount to procced.";
        case PARTPAID:
            yield "The order is partially paid. Some features will not be available. Please check the brochure for details.";
        case PAID:
            yield "The order is fully paid. Please choose the desired items from the menu.";
        default:
            throw new IllegalStateException("Invalid payment status: " + paymentStatus);
        };

        System.out.println(message);
    }
}

输出:

The order is partially paid. Some features will not be available. Please check the brochure for details.

1 添加了对 String 的支持 JDK 7

写得好!但我可能还会为单个案例语句添加多个案例的能力。下面的示例非常人为(有很多更好的方法可以实现)。它对字符串中的元音、数字、辅音和其他字符进行简单的频率计数。

int count[] = new int[4];

String s = "829s2bi9jskj*&@)(so2i2ksso";

for (char c : s.toCharArray()) {
      int i = switch (c) {
                case  'a', 'e', 'i', 'o', 'u' -> 0;
                case  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> 1;
                case  'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
                      'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w',
                      'x', 'y', 'z' -> 2;
                default -> 3;
      };
      count[i]++;
}
System.out.printf("vowels  - %d%n", count[0]);
System.out.printf("digits  - %d%n", count[1]);
System.out.printf("consonants - %d%n", count[2]);
System.out.printf("other   - %d%n", count[3]);

版画

vowels  - 4
digits  - 7
consonants - 10
other   - 5

添加到现有答案:yield 也可以与 -> 一起使用,其主要目的是在单个表达式不足以满足给定情况时允许使用块:

var test = switch (value) {
    case A -> 1;
    case B -> 2;
    case C -> {
        System.err.println("neither A nor B"); // or some calculation
        yield -1;
    }
}

我还会提到 JEP-354 提出和描述了 switch 表达式的地方。
可以找到正式规范,一如既往地在 Java Language Specification.