Explore Clojure's collection literals, including lists, vectors, maps, and sets, with examples and comparisons to Java.
In Clojure, collections are a fundamental part of the language, providing a rich set of data structures that are both immutable and persistent. As a Java developer, you may be accustomed to using arrays, lists, maps, and sets, but Clojure offers its own unique take on these data structures. In this section, we’ll explore the literal notations for Clojure’s core collection types: lists ()
, vectors []
, maps {}
, and sets #{}
. We’ll provide examples of each collection type with sample data, highlight the differences in usage between the collections, and offer tips on nested collections and how to read complex data structures.
()
§Lists in Clojure are ordered collections of elements, typically used for sequential processing. They are similar to Java’s LinkedList
, but with a key difference: Clojure lists are immutable. This means once a list is created, it cannot be changed. Lists are represented using parentheses ()
.
(def my-list '(1 2 3 4 5))
;; my-list is a list containing the numbers 1 through 5
Usage: Lists are ideal for scenarios where you need to process elements sequentially, such as in recursive functions. They are also used to represent code, as Clojure is a Lisp dialect.
Comparison with Java: In Java, you might use a LinkedList
for similar purposes, but remember that Java’s lists are mutable by default.
Diagram 1: A simple representation of a Clojure list.
[]
§Vectors are the go-to collection for indexed access in Clojure. They are similar to Java’s ArrayList
, providing fast access to elements by index. Vectors are represented using square brackets []
.
(def my-vector [1 2 3 4 5])
;; my-vector is a vector containing the numbers 1 through 5
Usage: Use vectors when you need efficient random access to elements. They are also commonly used for function arguments and return values.
Comparison with Java: Vectors in Clojure are akin to ArrayList
in Java, but with the added benefit of immutability.
graph TD; A[0: 1] --> B[1: 2]; B --> C[2: 3]; C --> D[3: 4]; D --> E[4: 5];
Diagram 2: A simple representation of a Clojure vector.
{}
§Maps in Clojure are collections of key-value pairs, similar to Java’s HashMap
. They are represented using curly braces {}
.
(def my-map {:a 1 :b 2 :c 3})
;; my-map is a map with keys :a, :b, :c and corresponding values 1, 2, 3
Usage: Maps are perfect for associative data, where you need to look up values by keys.
Comparison with Java: While Java’s HashMap
is mutable, Clojure’s maps are immutable, providing thread-safe access without synchronization.
graph TD; A{:a -> 1} --> B{:b -> 2}; B --> C{:c -> 3};
Diagram 3: A simple representation of a Clojure map.
#{}
§Sets in Clojure are collections of unique elements, similar to Java’s HashSet
. They are represented using hash braces #{}
.
(def my-set #{1 2 3 4 5})
;; my-set is a set containing the unique numbers 1 through 5
Usage: Use sets when you need to ensure uniqueness of elements.
Comparison with Java: Like Java’s HashSet
, Clojure’s sets ensure that each element is unique, but they are immutable.
graph TD; A{1} --> B{2}; B --> C{3}; C --> D{4}; D --> E{5};
Diagram 4: A simple representation of a Clojure set.
Clojure collections can be nested, allowing you to create complex data structures. This is similar to Java’s nested collections, but with the added benefit of immutability.
(def nested-collection
{:numbers [1 2 3]
:letters '(:a :b :c)
:sets #{#{1 2} #{3 4}}})
;; nested-collection is a map containing a vector, a list, and a set of sets
Reading Complex Data Structures: When dealing with nested collections, it’s important to understand the structure to access elements correctly. Use functions like get
, assoc
, and update
to navigate and manipulate nested data.
Experiment with the following code snippets: