從一小段代碼看 Clojure 和 Java 解決問題的差別

首先聲明一點,這篇短文不是要挑起語言之間的關於孰優孰劣的論戰,只是但願經過一個小需求,讓你們可以對比體會一下函數式編程和麪向對象編程的差別(包括理念和語法上的)。程序員


Clojure 是什麼?
Clojure 是運行在 Java 虛擬機(JVM)上的一種 Lisp 方言,她比 Common Lisp 更強調純函數式編程,同時擁有複雜的「宏」。具體能夠看 CSDN 上的一篇介紹文章 現實世界的LISP:Clojure語言初探 和知乎上的討論 請評價一下Clojure語言的設計redis

要解決一個什麼問題

咱們在開發過程當中常常會碰到這個需求,要對一個字符串進行哈希,而後當成 key 存入 redis。咱們準備使用 Java 的 SHA-512 哈希算子來作第一步運算,而且把結果再作一次 Base64 編碼轉換。算法

好的,那咱們接下來就看看在兩種語言中如何作到這一點吧。編程

Clojure 的解法

程序猿的世界,代碼說明一切,咱們直接上代碼吧,算法的入口是一個名爲 hash-name 函數:函數式編程

(defonce ^:private hash-key "universal_redis_hash_key")

(defn hash-name [k]
  (.substring ^String (:password (digest hash-key k)) 0 4))

(defn digest
  ([salt passwd]
     (digest "SHA-512" 512 salt passwd))
  ([hashalg iterations salt passwd]
     (let [jhash (MessageDigest/getInstance hashalg)
           new-pass (b64-encode (digester jhash salt passwd iterations))]
       {:salt salt :password new-pass})))

(defn- digester [^MessageDigest hasher ^String salt ^String pw-clear iter]
  {:tag String}
  (letfn [(hashme [hv]
            (letfn [(oneround [hv]
                      (do (.reset hasher)
                          (.digest hasher hv)))]
              (nth (iterate oneround hv) iter)))]
    (.reset hasher)
    (.update ^MessageDigest hasher (.getBytes salt))
    (.update ^MessageDigest hasher (.getBytes pw-clear))
    (hashme (.digest hasher))))

(defn b64-encode [^bytes b]
  {:tag String}
  (Base64/encodeBase64String b))

不知道能徹底看懂上面代碼的人有多少。要是咱們用Java寫出來的話,相信不少人會拍着腦殼:原來如此!函數

Java 的解法

仍是同樣,直接上代碼,這裏只有一個函數 hashName:編碼

private final static String hashKey = 「universal_redis_hash_key";

public static String hashName(String salt, String pw, int iter) {
    try {
        MessageDigest digest = MessageDigest.getInstance("SHA-512");
        digest.reset();
        digest.update(salt.getBytes());
        digest.update(pw.getBytes());
        byte[] temp = digest.digest();
        for (int i = 0; i < iter; i++) {
            digest.reset();
            temp = digest.digest(temp);
        }
        String result = Base64.encodeBase64String(temp);
        return result.substring(0, 4);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return "";
}

結論

對這兩門語言的見解,或許有人會從通俗易懂上進行比較,有人會從優雅嚴謹性上進行批判,我沒有任何傾向性,這就是一個仁者見仁智者見智的問題。翻譯

我只想補充說一下這種對比的由來。我司的程序員中 Clojure 粉較多,不少程序都是用 Clojure 寫的。最近要跟其餘公司的小夥伴合做搭一個服務,兩邊都須要採用一樣的關鍵字哈希算法。我找到一塊咱們的實現片斷,發了過去。可是對方不懂 Clojure,他們使用的是 Ruby;我懂 Clojure 可是不懂 Ruby,兩我的都快無法交流了。最後咱們一商量,你們都能懂 Java,因此我先把 Clojure 代碼翻譯成 Java 代碼,而後他再轉換成 Ruby 代碼,這樣兩邊的系統就對接上了。程序猿的語言世界真的好複雜!設計

相關文章
相關標籤/搜索