【问题标题】:Ternary operator in a foreach syntaxforeach 语法中的三元运算符
【发布时间】:2017-03-12 12:33:19
【问题描述】:

我有两个 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.

Foreach 不适用于 Object 类型。

这是为什么呢?

【问题讨论】:

  • 试试for(String it : columns.length > 0 ? Arrays.asList(columns) : FIELDS.keySet())这意味着常见的类型是Iterable<String>

标签: java collections foreach ternary-operator


【解决方案1】:

当您在三元组中使用两个表达式作为两个备选时,Java 需要确定它们的共同类型,以便确定表达式的类型。

由于columnsString[],而FIELDS.keySet()Set<String>,所以最好的常用类型是java.lang.Object。每个单独的类型都支持迭代,但公共基本类型不支持。这就是你得到错误的原因。

您可以通过将columns 转换为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)) {
    ...
}

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

另一个更高效的原因是 Java 编译器能够生成更高效的代码。正如T.J. Crowder 在下面提到的in his comment

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

您使用两个 foreach 的方法让编译器可以选择更适合集合类型的增强循环,而不是将两个集合硬塞到同一类型的对象中。

【讨论】:

  • 就我而言,转换不值得。简单的if for(x) else for(y) 会更合适,因为它是单行循环并且比副本消耗更少。谢谢你的解释!
  • @Spectre:还值得注意的是,Java 中实际上有两个enhanced for statements,而不仅仅是一个。其中一个循环遍历数组;另一个循环通过Iterables。编译器必须为它们发出不同的代码,具体取决于它处理的是数组还是Iterable
  • 或者,使用columns.length &gt; 0 ? Arrays.asList(columns) : FIELDS.keySet()
  • 顺便说一句,流操作使这一切更容易制定。
【解决方案2】:

这是因为三元运算符的两个部分必须共享相同的公共类型才能使它们符合 for-each 构造的条件。 for-each 构造需要Object[]Iterable

但是,在您的情况下,一个是array,另一个是Set。这两种类型最接近的共同父项是Object,因此它成为三元表达式的最终类型。

【讨论】:

  • 它们不需要是完全相同的类型,但它们都必须可以分配给Object[]Iterable
猜你喜欢
  • 1970-01-01
  • 2012-11-19
  • 1970-01-01
  • 2012-10-01
  • 2014-08-16
  • 2014-04-10
  • 1970-01-01
  • 2015-03-25
  • 2016-04-25
相关资源
最近更新 更多