资讯专栏INFORMATION COLUMN

从一小段代码看 Clojure 和 Java 解决问题的差异

aaron / 2613人阅读

摘要:的解法程序猿的世界,代码说明一切,我们直接上代码吧,算法的入口是一个名为函数不知道能完全看懂上面代码的人有多少。程序猿的语言世界真的好复杂

首先声明一点,这篇短文不是要挑起语言之间的关于孰优孰劣的论战,只是希望通过一个小需求,让大家能够对比体会一下函数式编程和面向对象编程的差异(包括理念和语法上的)。

  


Clojure 是什么?
Clojure 是运行在 Java 虚拟机(JVM)上的一种 Lisp 方言,她比 Common Lisp 更强调纯函数式编程,同时拥有复杂的「宏」。具体可以看 CSDN 上的一篇介绍文章 现实世界的LISP:Clojure语言初探 和知乎上的讨论 请评价一下Clojure语言的设计

要解决一个什么问题

我们在开发过程中经常会碰到这个需求,要对一个字符串进行哈希,然后当成 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 代码,这样两边的系统就对接上了。程序猿的语言世界真的好复杂!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64123.html

相关文章

  • JVM 平台上各种语言开发指南[z]

    摘要:我们的目标是建立对每一种语言的认识,它们是如何进化的,未来将走向何方。有点的味道是坚持使用动态类型,但唯一还收到合理拥泵的编程语言,然而一些在企业的大型团队中工作的开发者择认为这会是的一个缺陷。 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目。尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的JVM语言么? 如今借助来自...

    phodal 评论0 收藏0
  • 你应当知道7个Java工具

    摘要:如果应用发生了内存泄漏问题,就会进行检测生成报告,并且提供切实可行的方案去掉这个问题。主要特性实时的内存泄漏检测和告警一份包含时间,内存大小,速度以及泄漏事件的重要级别的报告。 在这篇文章中我们决定收集制作一个关于这类工具的简略名单,他们中的大多数工具只是最近推出的。其中一些工具是为Java定制的,但也有一些是支持其他语言。但对于Java项目而言,他们都是非常好的,并且拥有同一个愿景:...

    Pandaaa 评论0 收藏0
  • Java 8函数式编程》作者Richard Warbourton:Java亮点不是语言本身

    摘要:根据对社区和新特性的深刻理解,他创作了函数式编程一书。问你在伦敦社区的经历是否帮助你创作了函数式编程这本书绝对是这样。我认为引入函数式编程会为很多编程任务提供方便。问之前的是面向对象的,现在全面支持函数式编程。 非商业转载请注明作译者、出处,并保留本文的原始链接:http://www.ituring.com.cn/article/199271 Richard Warburto...

    mzlogin 评论0 收藏0
  • 我用ABAP做过那些无聊事情

    摘要:而且这种现象在德国的法定节假日里更加突出。所以本文提到的这些东西都是在德国节假日里无聊的产物,对于顾问的实际工作可能帮助不大。这也是在这篇文章里介绍的众多用搞出来的无聊的东西里唯一被官方认可的工具,囧。直接用执行里的事务码或者函数。 国庆大假马上就要来临了,我们聊点轻松的话题,关于假期。 Jerry的成都同事李贝宁(Li Ben), 《SAP成都研究院李三郎:SCP Applicati...

    wuaiqiu 评论0 收藏0
  • 函数范式入门(什么是函数式编程)

    摘要:第一节函数式范式什么是函数式编程函数式编程英语或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对象。 第一节 函数式范式 1. 什么是函数式编程 函数式编程(英语:functional programming)或称函数程序设计,又称泛函编程,是一种编程范型,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及易变对...

    StonePanda 评论0 收藏0

发表评论

0条评论

aaron

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<