Clojure语言十六 clojure与java

Clojure可以基于任何语言

Clojure诞生之初,是基于Java的。但是任何语言都可以解析lisp并执行,所以Clojure可以基于任何语言,只要一个大拿愿意这么干。这不,Clojurescript基于JavaScript的已经出现了, 之后又引发了另一个项目的出现ClojureC。两个项目在github上的地址:

https://github.com/clojure/clojurescript

https://github.com/schani/clojurec


Clojure和Java

现在来说说clojure与java的知识点。

将clojure代码编译成java代码

在core.clj文件中,可以添加一个list (:gen-class)用来生成java class, 比如我之前的博客中用过的

(ns hello-storm-clj.core
  (:import [backtype.storm StormSubmitter LocalCluster])
  (:use [backtype.storm clojure config])
  (:gen-class))

这样会将namespace hello-storm-clj编译成java类hello-strom-clj

将clojure工程编译成java包

参考之前的博客

主要命令是

lein do clean, uberjar  

原理是先编译出java class,然后生成manifest.mf文件,最后打包成jar文件,就可以当作java程序运行

clojure release jar包是如何运行的

clojure的历次发布都以jar包的形式,运行的命令和所有java程序一样

java -jar clojure-1.7.0.jar

解开clojure-1.7.0.jar包,找到里面的manifest.mf文件

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: hudson
Build-Jdk: 1.7.0_20
Main-Class: clojure.main

入口类是clojure.main类,在github中看其 源代码

package clojure;

import clojure.lang.Symbol;
import clojure.lang.Var;
import clojure.lang.RT;

public class main{

final static private Symbol CLOJURE_MAIN = Symbol.intern("clojure.main");
final static private Var REQUIRE = RT.var("clojure.core", "require");
final static private Var LEGACY_REPL = RT.var("clojure.main", "legacy-repl");
final static private Var LEGACY_SCRIPT = RT.var("clojure.main", "legacy-script");
final static private Var MAIN = RT.var("clojure.main", "main");

public static void legacy_repl(String[] args) {
    REQUIRE.invoke(CLOJURE_MAIN);
    LEGACY_REPL.invoke(RT.seq(args));
}

public static void legacy_script(String[] args) {
    REQUIRE.invoke(CLOJURE_MAIN);
    LEGACY_SCRIPT.invoke(RT.seq(args));
}

public static void main(String[] args) {
    REQUIRE.invoke(CLOJURE_MAIN);
    MAIN.applyTo(RT.seq(args));
}
}

一个正常的Java程序。里面的代码就不深究了。


clojure使用maven centre获取java依赖包

java生态圈极其庞大,调用java代码可以获得巨大的资源,clojure可以使用java库是个明智的决策。很多java依赖包都是通过maven centre组织的,因此要重复利用这个资源。前面介绍过,这里重复一下。

在project.clj中添加依赖,依赖参考pom.xml的maven依赖设置,org.apache.storm是groupId, storm-core是artifactId

:dependencies [[org.clojure/clojure "1.5.1"] [org.apache.storm/storm-core "0.9.5"]]

只要熟悉maven怎么用,用clojure获取java依赖就很简单。那些只用IDE从不看pom.xml的程序员就遭殃了。


clojure调用已有Java代码(java interop)

java interop就是值clojure能够调用java代码。

调用一个Java对象的方法

形如(.method-name object-variable arg1 arg2 ...),比如:

=>(.toUpperCase "call Java String")
"CALL JAVA STRING"
=> (.length "call Java String")
16

传个参数

e=> (.indexOf "call Java String" "S")
10

其实都使用的是dot operator,形如:

(. object-expr-or-classname-symbol method-or-member-symbol optional-args*)
kafka2hdfs.core=> (.indexOf "call Java String" "S")
10
kafka2hdfs.core=> (. "call Java String" indexOf "S")
10

因此两种形式都可以使用

设置一个Java对象的公有成员变量

语法如下:

(set! (.member-variable object-variable) new-value)

比如

(import java.awt.Point)

(let [pt (Point. 0 10)]
  (set! (.y pt) 100)
  (.y pt))  ; ⇒ 100

读取变量值很简单,  语法如下:

(.member-varible object-variable)

调用静态公有成员变量/函数

用/分开类和成员

(java.lang.Math/abs -3) 
; => 3

如何创建一个对象

两种方法(Class-name. arg1 arg2 ...)  这个最常用,还有就是(new Class-name arg1 arg2 ...)

注意,第一个方法里面有. 不要忘记了。

=> (String. "ok")
"ok"

连续调用一个对象的方法

(doto (java.util.Stack.)
  (.push "Latest episode of Game of Thrones, ho!")
  (.push "Whoops, I meant 'Land, ho!'"))

import java package

(import [package.name1 ClassName1 ClassName2]
        [package.name2 ClassName3 ClassName4])
比如:

(import [java.util Date Stack]
        [java.net Proxy URI])

(Date.)
; => #inst "2015-09-19T20:40:02.733-00:00"

放入namespace中是推荐的写法,也就是前面加上:

(ns pirate.talk
  (:import [java.util Date Stack]
           [java.net Proxy URI]))

访问一个类的内部类

用如下形式:package.class-name$inner-class

        rotation-policy (TimedRotationPolicy. 15.0 org.apache.storm.hdfs.bolt.rotation.TimedRotationPolicy$TimeUnit/MINUTES)

这里使用了内部静态枚举类TimeUnit的公有成员变量MINUTES,因为该类定义如下:

public class TimedRotationPolicy implements FileRotationPolicy {

    public static enum TimeUnit {

        SECONDS((long)1000),
        MINUTES((long)1000*60),
        HOURS((long)1000*60*60),
        DAYS((long)1000*60*60*24);

注意需要import

[org.apache.storm.hdfs.bolt.rotation TimedRotationPolicy]





你可能感兴趣的:(Clojure)