将Clojure函数有效地传递给java

时间:2016-10-07 09:24:24

标签: clojure clojure-java-interop

我想用Java循环在Java中实现一个天真的非惰性map。 我主要关注的是来自Clojure的java中的函数调用。

这是我的代码:

一个名为NaiveClojure的类,用于使用Java实现函数

package java_utils;

import java_utils.ApplyFn;

public class NaiveClojure {

    public static Object[] map (ApplyFn applyfn, Object function, Object[] coll) {

        int len = coll.length;

        for (int i = 0 ; i < len ; i++) {
            coll[i] = applyfn.apply(function, coll[i]);
        }

        return coll;
    }
}

一个名为ApplyFn的抽象类

package java_utils;

public abstract class ApplyFn {

  public abstract Object apply (Object function, Object value);

}

所以在Clojure中我有

(defn java-map [f coll]
  (let [java-fn (proxy [ApplyFn] []
                  (apply [f x]
                         (f x)))]
    (seq (NaiveClojure/map java-fn f (to-array coll)))))

我试过

(doall (map inc (range 0 10000))) ;; 3.4 seconds for 10000 operations
(java-map inc (range 0 10000) ;; 5.4 seconds

我的观点是不要超越map(我把它作为一个例子来实现),我只想做具有特定功能的事情(不要重新发明Clojure的轮子)。

有没有更好的方法来传递这样的功能? (作为一种简单快捷的方式) 为了改善我的编码(我的理论知识很差),你知道这里有什么杀戮吗? 我会说像Object这样的常规输入,但我没有看到任何其他内容

由于

1 个答案:

答案 0 :(得分:1)

这里你没有理由担心,你这样做的方式很好而且效率很高。

coll[i] = applyfn.apply(function, coll[i]);

这是一种非常正常的方式。正如Valentin Waeselynck指出的那样,在测量它时,请记住使用可靠的微基准测试功能,并记住单独对这种小代码块进行基准测试是非常棘手的。

当你生成一个clojure函数时,它产生一个&#34; normal&#34; java类,带有一个名为apply的方法。这样调用的速度会慢一些,因为您调用的函数最初是用Clojure编写的,而不是调用用普通Java语法编写的类的方法。一旦Hotspot JIT完成升温和内联,它可能会没有方法调用那么快(这就是为什么基准测试这种事情比直觉应该更难)。