Calling java from Clojure
Importing Java Class
In repl, when you want to import one Java class you can do
(import 'java.util.Date)
When you want to import more Java classes from a same package you can do
(import [java.util Date HashMap])
(ns com.techbehindtech.java
(:import [java.util Date HashMap]))
Creating Instances
(import 'java.util.Date) (def today (new Date)) ;; or (def today (Date.))
Calling Java instance methods
user> (import 'java.util.Date)
java.util.Date
user> (let [today (Date.)]
(.getTime today))
1286749020847
Calling Java static methods
user> (System/currentTimeMillis) 1286847946813
Sugar sytax:
Doto:
You want to write a function that will return UTC Java Calendar object set at a specific time.
user> (import [java.util Calendar TimeZone Date])
user> (defn utc-time [d]
(let [cal (Calendar/getInstance)]
(.setTimeZone cal (TimeZone/getTimeZone "UTC"))
(.setTime cal d)
cal))
#'user/utc-time
The let block is ugly. We could use doto to make this code better.
user> (import [java.util Calendar TimeZone Date])
user> (defn utc-time [d]
(doto (Calendar/getInstance)
(.setTimeZone (TimeZone/getTimeZone "UTC"))
(.setTime d)))
#'user/utc-time
Dot Dot:
Sometimes in java you want to make calls in chain
Bad way
user> (.length (.getProperty (System/getProperties) "user.country")) 2
Better way
user> (. (. (System/getProperties) getProperty "user.country") length) 2
Even Better
user> (..
(System/getProperties)
(getProperty "user.country")
(length))
2
Avoiding Reflection
By default jvm will be using reflection to identify type. Reflection is slow. But we can give type hints that way jvm does not have to use reflection. For example we can rewrite utc-time with type-hints like this
user> (set! *warn-on-reflection* true) true user> (defn str-length [s] (.length s)) Reflection warning, NO_SOURCE_FILE:1 - reference to field length can't be resolved. #'user/str-length user> (defn str-length [#^String s] (.length s)) #'user/str-length
Implementing interfaces and extending classes
Let us implement Java Runnable interface
user> (proxy [Runnable] []
(run []
(println "running ...")))
#<Object$Runnable$36fc6471 user.proxy$java.lang.Object$Runnable$36fc6471@6dd33544>
In clojure 1.2, you could use reify macro to implement. In fact it is better than using proxy.
user> (reify Runnable
(run [this]
(println "running ...")))
#<user$eval1664$reify__1665 user$eval1664$reify__1665@574f7121>
