CodeToLive

Clojure Java Interop

Clojure provides seamless interoperability with Java, allowing you to leverage existing Java libraries and frameworks while writing idiomatic Clojure code.

Basic Java Interop

Creating Java Objects


(def date (java.util.Date.)) ; Constructor
(def list (java.util.ArrayList.)) ; Empty ArrayList
(def list2 (java.util.ArrayList. [1 2 3])) ; ArrayList with elements
                

Calling Methods


(.toUpperCase "hello") ; => "HELLO"
(.substring "clojure" 2) ; => "ojure"
(.getName String) ; => "java.lang.String"
                

Static Methods


(Math/sqrt 25) ; => 5.0
(System/currentTimeMillis)
                

Accessing Fields


(.-x (java.awt.Point. 10 20)) ; => 10
(.-MAX_VALUE Integer) ; => 2147483647
                

Importing Java Classes

Single Import


(import 'java.util.Date)
(def now (Date.))
                

Multiple Imports


(import '(java.util Date Calendar)
(import '(java.awt Point Rectangle))
                

ns Declaration


(ns my.app
  (:import [java.util Date Calendar]
           [java.awt Point Rectangle]))
                

Working with Java Collections

Converting Between Collections


(def jlist (java.util.ArrayList. [1 2 3]))
(def clist (seq jlist)) ; Convert to Clojure seq
(def jlist2 (java.util.ArrayList. clist)) ; Back to Java list
                

Using Java Collections


(def hashmap (java.util.HashMap.))
(doto hashmap
  (.put "a" 1)
  (.put "b" 2))

(seq hashmap) ; => (["a" 1] ["b" 2])
                

Exception Handling

try-catch


(try
  (/ 1 0)
  (catch ArithmeticException e
    (println "Caught exception:" (.getMessage e)))
                

finally


(try
  (some-risky-operation)
  (catch Exception e
    (handle-error e))
  (finally
    (clean-up)))
                

Implementing Java Interfaces

Anonymous Implementation


(def runnable
  (reify Runnable
    (run [this]
      (println "Running"))))

(.start (Thread. runnable))
                

Implementing Multiple Interfaces


(def listener
  (reify 
    java.awt.event.ActionListener
    (actionPerformed [this e]
      (println "Action performed"))
    
    java.lang.Runnable
    (run [this]
      (println "Running"))))
                

Extending Java Classes


(def my-frame
  (proxy [javax.swing.JFrame] []
    (paint [g]
      (proxy-super paint g)
      (.drawString g "Hello" 50 50))))
                

Java Arrays

Creating Arrays


(def int-array (int-array [1 2 3]))
(def str-array (into-array String ["a" "b" "c"]))
(def multi-array (make-array Integer/TYPE 2 3))
                

Working with Arrays


(aget int-array 1) ; => 2
(aset int-array 1 99) ; Set element
(alength int-array) ; => 3
(seq int-array) ; => (1 99 3)
                

Advanced Interop

Varargs Methods


; Java: void printf(String format, Object... args)
(.printf System/out "%s %d" (into-array Object ["value:" 42]))
                

Primitive Types


(defn sum [^long a ^long b]
  (+ a b))
                

Annotations


(defn ^{Deprecated true} old-function []
  "This is deprecated")
                

Calling Clojure from Java

Loading Clojure Code


// Java code
import clojure.java.api.Clojure;
import clojure.lang.IFn;

public class ClojureCaller {
    public static void main(String[] args) {
        IFn require = Clojure.var("clojure.core", "require");
        require.invoke(Clojure.read("my.clojure.ns"));
        
        IFn cljFunction = Clojure.var("my.clojure.ns", "my-function");
        Object result = cljFunction.invoke("arg1", 42);
    }
}
                

Generating Java Classes


(ns my.genclass
  (:gen-class
   :name my.Person
   :implements [java.lang.Runnable]
   :methods [[getName [] String]
             [setName [String] void]))
                

Performance Considerations

  • Use type hints to avoid reflection
  • Prefer Clojure collections for Clojure code
  • Consider Java arrays for performance-critical numeric code
  • Be mindful of boxing/unboxing with primitives

Common Java Libraries

java.util.concurrent


(def exec (java.util.concurrent.Executors/newFixedThreadPool 4))
(.submit exec #(println "Running task"))
                

java.nio


(def path (java.nio.file.Paths/get "file.txt" (into-array String [])))
(def lines (java.nio.file.Files/readAllLines path))
                

java.time


(def now (java.time.LocalDateTime/now))
(def tomorrow (.plusDays now 1))
                

Next Steps

Continue learning with: