Toby Hede
Toby Hede

Reputation: 37133

Converting Java collections to Clojure data structures

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?

Upvotes: 5

Views: 1803

Answers (3)

mikera
mikera

Reputation: 106351

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.

Upvotes: 12

skuro
skuro

Reputation: 13514

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"}

Upvotes: 2

Joost Diepenmaat
Joost Diepenmaat

Reputation: 17773

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> 

Upvotes: 2

Related Questions