I need to create and populate an ArrayList in clojure and pass it to an Java API. Can someone help explain why there is a difference in the below two approaches (and why one of them doesn't work).
;;; this works
(defn make-an-array-list []
(let [alist (java.util.ArrayList.)]
(loop [x 0] (when (< x 6) (.add alist x) (recur (inc x)))) alist))
;;; ==> [0 1 2 3 4 5]
;;; this does not work
(defn make-an-array-list2 []
(let [alist (java.util.ArrayList.)]
(for [n (range 6)] (.add alist n)) alist))
;;; ==> []
Or, any suggestion in stead of the above approach?
Better still, just write (ArrayList. (range 6))
. Or if the java code is well written, and only requires an Iterable, List, or Collection - anything less specific than ArrayList - you can simply return (range 6)
.
Use doseq
instead of the lazy for
. It has for-like bindings but it's meant for side-effects.
(defn make-an-array-list2 []
(let [alist (java.util.ArrayList.)]
(doseq [n (range 6)] (.add alist n)) alist))
;; [0 1 2 3 4 5]
Here is a more explicit answer for why the second example doesn't work. The for
expression is lazy; in other words, it isn't evaluated unless its result are consumed by something. You throw away the result of the for
expression because you only care about the side-effects, so it's never actually evaluated.
Here is an example of the same phenomenon:
(defn example[]
(for [n (range 6)]
(println "n=" n))
(println "done"))
(example)
;; done
;; nil
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