UP | HOME

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)))

常用的操作就这些,很实用很不错。