foreach语法中的三元运算符

1 java collections foreach ternary-operator

我有两个String集合:String... columns- 这只是一个简单的数组和KeySet<String>一个地图.

for(String it : columns) // works
for(String it : FIELDS.keySet()) // works
for(String it : ((columns.length > 0) ? columns : FIELDS.keySet())) // doesn't.
Run Code Online (Sandbox Code Playgroud)

Foreach不适用于Object类型.

这是为什么?

das*_*ght 5

当您在三元组中使用两个表达式作为两个替代方案时,Java需要决定它们的常见类型,以便确定表达式的类型.

既然columnsString[],FIELDS.keySet()也是Set<String>最好的常见类型java.lang.Object.每种类型都支持迭代,但公共基类型不支持迭代.这就是你得到错误的原因.

您可以通过转换columns为a Set<String>或转换FIELDS.keySet()String[]:

Set<String> keySet = FIELDS.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()])
for(String it : ((columns.length > 0) ? columns : keyArray)) {
    ...
}
Run Code Online (Sandbox Code Playgroud)

(来自评论)在我的情况下,转换不值得.简单if for(x) else for(y)适合更好,因为它是一个单行循环,比副本消耗更少.

这更有效的另一个原因是Java编译器能够生成更高效的代码.正如TJ Crowder 下面的评论中指出的那样,

[Java]编译器必须为它们发出不同的代码,具体取决于它是处理数组还是处理数组 Iterable

使用two的方法foreach可以让编译器选择一个更适合集合类型的增强循环,而不是将两个集合强制转换为相同类型的对象.

  • @Spectre:值得注意的是,实际上有两个[增强的`for`陈述](https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.14 .2)在Java中,而不仅仅是一个.其中一个循环遍历数组; 另一个循环通过`Iterable`s.编译器必须为它们发出*不同的*代码,这取决于它是处理数组还是"Iterable". (3认同)
  • 或者,使用`columns.length> 0?Arrays.asList(columns):FIELDS.keySet()`. (2认同)