Clojure 与 Java 交互
作为活在jvm上的语言,并且把使用 java 库作为自己的优势,与 java 的调用绝不可避免。所以,这个知识很重要。
使用 java 文件
之前在 ns 中,有说过这个,如何引入 java 的文件。
语法: (import & import-symbols-or-lists)
实例:
(import '(org.apache.hadoop.hbase.client HTable Scan Scanner) '(org.apache.hadoop.hbase.filter RegExpRowFilter StopRowFilter)) ;; 或者 (ns com.clojureinaction.book (:import (java.util Set)))
创建实例
一个实例的创建,通过类名和一个点(.)即可,如下:
(import '(java.text SimpleDateFormat)) (def sdf (Simpledateformat. "yyyy-MM-dd"))
方法和成员变量
静态方法
静态方法调用,语法: (Classname/staticMethod args)。
实例如下:
(Long/parseLong "12321")
公开非静态方法
采用一个 . 宏操作符号,实例如下:
(defn date-from-date-string [date-string] (let [sdf (SimpleDateFormat. "yyyy-MM-dd")] (.parse sdf date-string)))
同时还有一种方法,格式为: (. Classname-symbol method-symbol args) 或者 (. Classname-symbol (method-symbol args))
实例如下:
(import '(java.util Random)) (let [rnd (Random. )] (. rnd (nextInt 10))) ;; 也可以写成: (.nextInt rnd 10)
公开成员变量
使用 . 宏操作,还可以获取到类的成员变量,格式为: (. Classname-symbol member-symbol) 或者 (. instance-expr member-symbol) 。
实例如下:
(. Calendar DECEMBER)
.. 宏
写过 java 的都知道,这个语言比较啰嗦。以 《Clojure in Action》中的获取当前时区名字为例, 按照 . 的用法,是可以逐步获取日历的实例,然后点操作获取时区类,再点操作获取时区名,需要进行嵌套,代码比较冗长,会是下面这个样子:
(import '(java.util Calendar TimeZone)) (. (. (Calendar/getInstance) (getTimeZone)) (getDisplayName))
这样的代码看上去简直难以接受,类的获取再深入一点,可能要嵌套多层。 .. 宏就是应对这个问题的,使用 .. 之后,代码如下:
(import '(java.util Calendar TimeZone)) (.. (Calendar/getInstance) (getTimeZone) (getDisplayName true TimeZone/SHORT))
最后一个 getDisplayname 方法接收了两个参数。
doto
doto 是一个懒人宏,主要是为了一个实例,连续调用它的N个方法设立的。比如以下这个给日历设置时间的操作:
(import '(java.util Calendar)) (defn the-past-midnight-1 [] (let [calendar-obj (Calendar/getInstance)] (.set calendar-obj Calendar/AM_PM Calendar/AM) (.set calendar-obj Calendar/HOUR 0) (.set calendar-obj Calendar/MINUTE 0) (.set calendar-obj Calendar/SECOND 0) (.set calendar-obj Calendar/MILLISECOND 0) (.getTime calendar-obj)))
有了 doto 后,会少一些代码。如下:
(defn the-past-midnight-2 [] (let [calendar-obj (Calendar/getInstance)] (doto calendar-obj (.set Calendar/AM_PM Calendar/AM) (.set Calendar/HOUR 0) (.set Calendar/MINUTE 0) (.set Calendar/SECOND 0) (.set Calendar/MILLISECOND 0)) (.getTime calendar-obj)))
常用的操作就这些,很实用很不错。