在Clojure中检测对象是否是Java基元数组的最佳方法是什么?
我需要这样做的原因是对基元数组进行一些特殊处理,它可能看起来像:
(if (byte-array? object)
(handle-byte-array object))
它在一段对性能相当敏感的代码中,所以如果可能的话,我宁愿避免反思。
您可以使用反射一次从名称中获取类,缓存它,然后将其余部分与进行比较
(def array-of-ints-type (Class/forName "[I"))
(def array-of-bytes-type (Class/forName "[B"))
...
(= (type (into-array Integer/TYPE [1 3 4])) array-of-ints-type)
true
(defn primitive-array? [o]
(let [c (class o)]
(and (.isArray c)
(.. c getComponentType isPrimitive))))
对于特定情况,您可以使用以下内容:
(defn long-array? [o]
(let [c (class o)]
(and (.isArray c)
(identical? (.getComponentType c) Long/TYPE))))
要在不使用反射的情况下检查字节数组,可以执行以下操作:
(def ^:const byte-array-type (type (byte-array 0)))
(defn bytes? [x] (= (type x) byte-array-type))
不完全确定原因,但您甚至可以使用^:const
内联字节数组类型。
正如Arthur Ulfeldt所指出的,您可以使用Class/forName
,例如,如下所示:
(def byte_array_class (Class/forName "[B"))
(defn byte-array? [arr] (instance? byte_array_class arr))
如果您想在缓存类时避免像"[B"
这样的魔术字符串,可以将class
应用于现有的数组对象:
(def byte_array_class (class (byte-array [])))
或普通旧instance?
:
(instance? (RT/classForName "[B") thing)
支持所有其他答案。这是一条单行线:
(def byte-array? (partial instance? (Class/forName "[B")))
有关其他基元,请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29(或java规范)。或者按照Gerrit的建议使用(type (xyz-array 0))
。具体来说,您可以使用:
"[Z" boolean array
"[B" byte array
"[C" char array
"[D" double array
"[F" float array
"[I" integer array
"[J" long array
"[S" short array
既然提到了性能,下面是运行(time (dotimes [_ 500000] (byte-array? x)))
和byte-array-class
定义的的一个小的基准测试结果
(def byte-array? (partial instance? (Class/forName "[B")))
78.518335 msecs
(defn byte-array? [obj] (instance? byte-array-class obj))
34.879537 msecs
(defn byte-array? [obj] (= (type obj) byte-array-class))
49.68781 msecs
instance?
vs type
=实例?赢得
partial
vs defn
=defn赢得
但这些方法中的任何一种都可能不会成为性能的瓶颈。
由于Clojure 1.9,您可以使用bytes?
字节吗?文档链接