增强的switch语句是否可以有多个值赋值?

7
我尝试使用增强的switch语句初始化两个变量:
```html

我尝试使用增强的switch语句初始化两个变量:

```
int num = //something

boolean val1;
String val2;

val1, val2 = switch(num) {
    case 0 -> (true, "zero!");
    case 1 -> (true, "one!");
    default -> (false, "unknown :/");
}

这个可能吗?

5个回答

6

由于您已经使用Java-13,我建议不要使用额外的库来表示元组,而是使用Map.entry(在Java-9中引入)并利用局部变量类型var推断的语法糖。

var entry = switch (num) {
    case 0 -> Map.entry(true, "zero!");
    case 1 -> Map.entry(true, "one!");
    default -> Map.entry(false, "unknown :/");
};
boolean val1 = entry.getKey();
String val2 = entry.getValue();

1
不错,我不知道Map.entry()这个快捷方式...我不知道为什么我总是犹豫不决地使用Entry来保存任意数据(超出“map”上下文之外的数据)... - ernest_k
1
@ernest_k 但是你需要记住,Map.entry() 对于 null 的严格策略与 Map.of() 相同。 - Holger

4
将两个变量的初始化揉入一个语句中并没有必要。与之对比,可以这样写:
var val1 = switch(num) { case 0, 1 -> true; default -> false; };
var val2 = switch(num) { case 0 -> "zero!"; case 1 -> "one!"; default -> "unknown :/"; };

为了完整性,新的switch语法也允许赋值:

boolean val1;
String val2;
switch(num) {
    case 0 -> { val1 = true; val2 = "zero!"; }
    case 1 -> { val1 = true; val2 = "one!"; }
    default -> { val1 = false; val2 = "unknown :/"; }
}

您可以使用表达式形式为一个变量提供初始化程序并将其赋值给另一个变量。
boolean val1;
String val2 = switch(num) {
    case 0 -> { val1 = true; yield "zero!"; }
    case 1 -> { val1 = true; yield "one!"; }
    default -> { val1 = false; yield "unknown :/"; }
};

但是如果你不喜欢它,我也不会感到惊讶。对于这个特定的例子,只使用

var val2 = switch(num) { case 0 -> "zero!"; case 1 -> "one!"; default -> "unknown :/"; };
var val1 = !val2.equals("unknown :/");

首先,将这两个属性包装起来有一个好处,比如在需要检索时不会失去耦合。当然,我并不否认一个简单的“类”定义也可以解决这个问题,并提供额外的可扩展性。此外,目前OP所采用的方法,理想情况下应该返回元组,以便更好地理解执行“switch”的方法。但是,这可能需要对需求和设计进行更详细的阐述。 - Naman
2
@Naman 当关注的是值的耦合性(而不是初始化变量)时,数据结构是一个合适的选择,但是,不要半途而废,创建一个静态的 final Map 包含这些对象,并用 map 查找替换 switch 语句/表达式...甚至可以创建一个专门封装 booleanString(甚至更多)的类型,而不是使用通用的 PairEntry 对象。 - Holger
1
我非常赞同,而且我会坚持认为需要更多关于问题背景的上下文信息,才能理解设计并做出整体决策......这与我在之前评论中提到“类”的方向类似。 - Naman

3

Java中没有元组解包。一个快速的替代方法仍然可以使用switch表达式,可以使用自定义类(在以下示例中使用Pair):

Pair<Boolean, String> val = switch (num) {
    case 0 -> Pair.of(true, "zero!");
    case 1 -> Pair.of(true, "one!");
    default -> Pair.of(false, "unknown :/");
};

boolean val1 = val.getLeft();
String val2 = val.getRight();

@AllenLiao,虽然这并不需要使用额外的库(https://dev59.com/S7noa4cB1Zd3GeqPMDNH#60180440)。 - Naman
1
boolean val1 = num == 0 || num == 1; String val2 = val1? List.of("zero!", "one!").get(num): "unknown :/"; - Holger
1
@Naman 无论您使用 Map.entry(true, "zero!") 还是 Pair.of(true, "zero!");,我不确定这是否比 { val1 = true; val2 = "zero!"; }(与我的答案相比)有显着的优势,因为这些值必须在两个额外的语句中提取(或者如果有的话,这种好处是否可以证明自动装箱和创建临时包装实例的开销)。 - Holger

1
简短回答,Java不支持多重赋值的方式,至少在我所知道的范围内是不支持的。 一种解决方法是建立一个容器类,其中存储一个字符串和布尔值。
例子:
class Response 
{
    String message;
    boolean found;
}

并返回包含两者的对象。
或者您可以使用数组和类型转换,或者不同结构的语句。

switch(num) {
    case 0: 
        val1 = true;
        val2 = "zero!"
        break;
    case 1: 
        val1 = true;
        val2 = "one!"
        break;
    default: 
        val1 = false;
        val2 = "unknown :/"
        break;
}

1
另一个选项(在Java 14中作为预览功能引入,并从Java 16开始成为标准功能)是使用记录作为容器来返回您希望返回的两个值。
这样可以减少您需要编写的样板代码,以创建一个保存这两个值的常规类,同时与使用Map.Entry或Pair类相比提供更好的可读性。
record Something (boolean boolField, String strField) {};

var result = switch(num) {
    case 0 -> new Something (true, "zero!");
    case 1 -> new Something (true, "one!");
    default -> new Something (false, "unknown :/");
};
boolean val1 = result.boolField ();
String val2 =  result.strField ();

请注意,您应该使用能够描述此记录及其字段目的的有意义的名称,而不是使用SomethingboolFieldstrField

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接