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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With