I am writing Clojure code interacting with external Java library. One of the method returns Java Optional
object. Let's assume that it returns Optional<String>
and I need to change the string value in the Optional
object, for example, to lowercase. I'd use map
method if I write the code in Java:
Optional<String> ret = someObj.someMethod();
ret.map(String::toLowerCase)
.map(...)
.orElse("x");
So, I need to call someObj.someMethod()
in Clojure and have to do the similar work. What I found is this: Passing a Clojure function as java.util.Function
So I wrote code like this:
(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")))
In order to pass clojure function to the place that expects Java lambda, I used jfn
defined like the above. And actually it works fine.
But I am not sure this is the best way to do this as I have to wrap clojure function that calls Java method inside with Java's Function
.
Are there any better/simpler way to do this? It will be better if we can call Java String
's toLowerCase
method directly.
I'm not sure if it fits your use case, but you could "unbox" the Optional
early on, and use some->
macro to do similar short-circuit-on-null function composition.
Even if you needed an Optional
with the value later, it might be easier to unbox the value early and re-box the value later, rather than Function
interop.
(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"
Then if you needed to convert back to Optional
:
(Optional/ofNullable *1)