【问题标题】:Dealing with Java Optional<T> in clojure在 clojure 中处理 Java Optional<T>
【发布时间】:2020-07-14 07:49:19
【问题描述】:

我正在编写与外部 Java 库交互的 Clojure 代码。其中一种方法返回 Java Optional 对象。假设它返回Optional&lt;String&gt;,我需要将Optional 对象中的字符串值更改为小写。如果我用 Java 编写代码,我会使用 map 方法:

Optional<String> ret = someObj.someMethod();
ret.map(String::toLowerCase)
   .map(...)
   .orElse("x");

所以,我需要在 Clojure 中调用 someObj.someMethod() 并且必须做类似的工作。我发现是这样的:Passing a Clojure function as java.util.Function

所以我写了这样的代码:

(defn ^java.util.function.Function jfn [f]
  (reify java.util.function.Function
    (apply [this arg] (f arg))))

(let [ret (.someMethod someObj)]
  (.. ret
      (map (jfn (fn [x] (s/lower-case x))))
      (map (jfn (...)))
      (orElse "x")))

为了将 clojure 函数传递到需要 Java lambda 的地方,我使用了如上定义的jfn。实际上它工作得很好。

但我不确定这是不是最好的方法,因为我必须用 Java 的 Function 包装调用 Java 方法的 clojure 函数。

有没有更好/更简单的方法来做到这一点?如果我们可以直接调用JavaStringtoLowerCase方法就更好了。

【问题讨论】:

  • 我不确定它是否适合您的用例,但您可以尽早“拆箱”Optional,并使用some-&gt; 宏执行类似操作。即使您稍后需要一个带有值的Optional,也可能比执行函数互操作更容易重新装箱该值。
  • @TaylorWood 感谢您的反馈。我认为您的想法是有效的,值得作为答案。
  • 我更喜欢你的第一种方法。如果您不喜欢装箱,并且您的函数都是文字,您可以将 jfn 设为宏而不是函数:(defmacro jfn [[arg] &amp; body] (reify Function (apply [_# ~arg] ~@body))),然后是 (.map ret (jfn [x] (s/lower-case x)))

标签: java clojure clojure-java-interop


【解决方案1】:

我不确定它是否适合您的用例,但您可以尽早“拆箱”Optional,并使用some-&gt; 宏来执行类似的空值短路函数组合。

即使您稍后需要一个带有值的Optional,与Function 互操作相比,提前拆箱并稍后重新装箱可能更容易。

(defn optional->nilable [this]
  (when (.isPresent this)
    (.get this)))

(def maybe (Optional/of " something "))

(some-> (optional->nilable maybe)
        (clojure.string/trim)
        (not-empty)
        (clojure.string/upper-case))
; => "SOMETHING"

那么如果你需要转换回Optional:

(Optional/ofNullable *1)

【讨论】:

  • 你也可以展开内联,(some-&gt; (.orElse maybe nil) ,,,) ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多