Converting Java collections to Clojure data structures
Asked Answered
M

3

5

I am creating a Clojure interface to a Java API with a method that returns a java.util.LinkedHashSet.

Firstly, is the idiomatic Clojure way of handling this to convert the LinkedHashSet to a clojure data structure?

Secondly, what is the best method for converting Java collections into Clojure data structures?

Maturity answered 14/2, 2012 at 10:42 Comment(0)
M
12

There are lots of options, since Clojure plays very nicely with Java collections. It depends on exactly what data structure you want to use in Clojure.

Here's some examples:

;; create a HashSet
(def a (java.util.HashSet.))
(dotimes [i 10] (.add a i))

;; Get all the values as a sequence 
(seq a)
=> (0 1 2 3 4 5 6 7 8 9)

;; build a new HashSet containing the values from a 
(into #{} a)
#{0 1 2 3 4 5 6 7 8 9}

;; Just use the HashSet directly (high performance, no copy required)
(.contains a 1)
=> true
(.contains a 100)
=> false

Regarding when to use each of these, I'd suggest the following advice:

  • If you are trying to wrap a Java library and present a clean Clojure API, then I'd suggest converting to the equivalent Clojure data structures. This is what Clojure users will expect, and you can hide the potentially messy Java interop details. As a bonus, this will make things immutable so that you don't run the risk of Java collections mutating while you use them.
  • If you just want to use the Java API quickly and efficiently, just use Java interop directly on the Java collections.
Metapsychology answered 14/2, 2012 at 10:53 Comment(0)
I
2

The idiomatic way to convert java collections to clojure is to use the (seq) function, which is already called by most functions operating on sequences.

(def s (java.util.LinkedHashSet.))
#'user/s
user> (seq s)
nil
user> (.add s "foo")
true
user> (seq s)
("foo")
user> 
Informant answered 14/2, 2012 at 10:52 Comment(0)
R
2

I honestly don't know if there's a universally accepted practice, but here's Chris Houser arguing against Java to Clojure adapters as you break compatibility with the original Java API.

To perform the translation you asked for, simply use into:

user=> (import java.util.LinkedHashSet)
java.util.LinkedHashSet
user=> (def x (LinkedHashSet.))
#'user/x
user=> (.add x "test")
true
user=> (def y (into #{} x))
#'user/y
user=> y
#{"test"}
Runthrough answered 14/2, 2012 at 10:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.