2012-07-10 66 views
5

我正在clojure中使用java类,它为包含一系列记录的域特定二进制文件提供检索API。clojure a与非标准迭代java API的互操作性

java类初始化为一个文件,然后提供一个.query方法,该方法返回一个只有一个方法.next的内部类的实例,因此不能很好地与通常的Java集合API一起玩。外层和内层类都不实现任何接口。

.query方法可能会返回null而不是内部类。 .next方法返回一个记录字符串,如果没有找到其他记录,则返回null,它可能在第一次调用时立即返回null。

如何让这个java API在clojure中很好的工作而无需编写更多的java类?

我能想出的最好的是:


(defn get-records 
    [file query-params] 
    (let [tr (JavaCustomFileReader. file)] 
    (if-let [inner-iter (.query tr query-params)] ; .query may return null                
     (loop [it inner-iter 
      results []] 
     (if-let [record (.next it)] 
     (recur it (conj results record)) 
     results)) 
     []))) 

这给我结果的矢量与Clojure的序列抽象的工作。有没有其他的方法可以通过lazy-seq或使用协议来暴露java API中的seq?

+0

这是一个有趣的问题,但是您是指非标准Java API的含义? – octopusgrabbus 2012-07-10 15:06:23

+0

@octopusgrabbus具体而言,我的意思是Java代码不提供java.util.Iterator,也不实现java.lang.Iterable。逻辑上,Java代码提供迭代,但没有与标准API的连接。 – 2012-07-10 15:14:55

回答

4

没有下降到lazy-seq

(defn record-seq 
    [q] 
    (take-while (complement nil?) (repeatedly #(.next q)))) 

相反(complement nil?),你也可以只使用identity如果.next不返回布尔false

(defn record-seq 
    [q] 
    (take-while identity (repeatedly #(.next q)))) 

我也会重组一点点的入口点。

(defn query 
    [rdr params] 
    (when-let [q (.query rdr params)] 
    (record-seq q))) 

(defn query-file 
    [file params] 
    (with-open [rdr (JavaCustomFileReader. file)] 
    (doall (query rdr params)))) 
+0

不错的解决方案! – Gert 2012-07-11 10:56:37

4

您的代码并不像使用Iterable那样懒,但您可以使用lazy-seq填充空格,如下所示。

(defn query-seq [q] 
    (lazy-seq 
    (when-let [val (.next q)] 
     (cons val (query-seq q))))) 

也许你会包裹查询方法以保护你自己的第一个null值。

+2

将“lazy-seq”移到'when-let'周围。 – 2012-07-10 19:19:25

4

似乎是一个非常适合lazy-seq

(defn query [file query] 
    (.query (JavaCustomFileReader. file) query)) 

(defn record-seq [query] 
    (when query 
    (when-let [v (.next query)] 
     (cons v (lazy-seq (record-seq query)))))) 

;; usage: 
(record-seq (query "filename" "query params"))