【问题标题】:How do I rewrite this java function in scala keeping the same Optional input parameter?如何在 scala 中重写这个 java 函数,保持相同的可选输入参数?
【发布时间】:2020-01-07 18:23:56
【问题描述】:

我在java中有以下方法

protected <T> T getObjectFromNullableOptional(final Optional<T> opt) {
    return Optional.ofNullable(opt).flatMap(innerOptional -> innerOptional).orElse(null);
}

它需要一个 java Optional,它本身可以是 null(我知道,这真的很糟糕,我们最终会解决这个问题)。它用另一个Optional 包裹它,所以它变成Some(Optional&lt;T&gt;)None。然后是flatMapped,所以我们返回Optional&lt;T&gt;或者None,最后申请orElse()得到T或者null

如何在 scala 中使用相同的 java.util.Optional 编写相同的方法?

protected def getObjectFromNullableOptional[T >: Null](opt : Optional[T]): T =
    ???

我试过了

protected def getObjectFromNullableOptional[T >: Null](opt : Optional[T]): T =
  Optional.ofNullable(opt).flatMap(o  => o).orElse(null)

但这给了我一个Type mismatch 错误

必需:函数[_ >:可选[T],可选[NotInferedU]]

找到:没有 => 没有

我试过了

protected def getObjectFromNullableOptional[T >: Null](opt : Optional[T]): T =
  Option(opt).flatMap(o => o).getOrElse(null)

但这给了我

无法解析重载方法“flatMap”

编辑我没有提到我使用的是 scala 2.11。我相信@tefanobaghino 的解决方案适用于 scala 2.13,但它引导我走向正确的道路。我把我的最终解决方案放在这个解决方案下的 cmets 中

【问题讨论】:

  • IMO 返回 null 而不是选项/可选不是一个好主意。输出应该是Option[T]

标签: java scala optional scala-option


【解决方案1】:

最后一个错误引起了一些怀疑:看起来您将 Java Optional 包装在 Scala Option 中。相反,我本来希望这会失败,因为您正在尝试将 flatMap 转换为其他类型,例如

error: type mismatch;
 found   : java.util.Optional[T] => java.util.Optional[T]
 required: java.util.Optional[T] => Option[?]

这似乎满足您的要求:

import java.util.Optional

def getObjectFromNullableOptional[T](opt: Optional[T]): T =
  Optional.ofNullable(opt).orElse(Optional.empty).orElse(null.asInstanceOf[T])

assert(getObjectFromNullableOptional(null) == null)
assert(getObjectFromNullableOptional(Optional.empty) == null)
assert(getObjectFromNullableOptional(Optional.of(1)) == 1)

你可以玩这个here on Scastie

请注意,asInstanceOf 被编译为强制转换,而不是实际的方法调用,因此此代码不会抛出 NullPointerException

您还可以通过帮助 Scala 的类型推断来更接近您的原始解决方案:

def getObjectFromNullableOptional[T](opt: Optional[T]): T =
  Optional.ofNullable(opt).flatMap((o: Optional[T]) => o).orElse(null.asInstanceOf[T])

或者使用 Scala 的 identity:

def getObjectFromNullableOptional[T](opt: Optional[T]): T =
  Optional.ofNullable(opt).flatMap(identity[Optional[T]]).orElse(null.asInstanceOf[T])

对于使用 Scala 的Option 的解决方案,您可以做一些非常接近的事情:

def getObjectFromNullableOption[T](opt: Option[T]): T =
  Option(opt).getOrElse(None).getOrElse(null.asInstanceOf[T])

请注意,使用 Scala 的 Option 转到 flatMap 解决方案可以避免必须明确说明函数类型:

def getObjectFromNullableOption[T](opt: Option[T]): T =
  Option(opt).flatMap(identity).getOrElse(null.asInstanceOf[T])

我不完全确定具体细节,但我认为问题在于,当使用 java.util.Optional 时,您将 Scala Function 传递给 Optional.flatMap,这需要 Java Function。 Scala 编译器可以自动为您转换它,但显然您必须具体明确类型才能使其工作,至少在这种情况下是这样。

关于您的原始代码的注释:您要求 TNull 的超类型,但这不是必需的。

您对正在做的事情有更好的了解,但作为一般建议,通常最好避免在 Scala 代码中出现nulls 泄漏。

【讨论】:

  • 我没有提到我正在使用 scala 2.11,所以我不得不稍微修改你的建议以使其正常工作:Optional.ofNullable(opt).orElse(Optional.empty[T]).orElse(null.asInstanceOf[T])
猜你喜欢
  • 2022-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
相关资源
最近更新 更多