clojure java_Clojure:Java的成熟替代品

clojure java

今年,我们庆祝Java 25周年,它是目前最流行的编程语言。 也就是说,根据TIOBE index 。 成为最流行的编程语言是一项艰巨的任务,并且肯定在Java诞生之初就需要说服许多人。

这就是Java当时被定位为更好地替代所选语言的方式:

“我们追求的是C ++程序员。 我们设法将其中许多拖到Lisp的中间位置。”

— Guy Steele,Java语言规范的合著者

这样一来,许多程序员开始使用Java,进入启蒙之路的中途。 这篇文章是关于后续部分中,切换到Lisp的...或者在任何情况下: 口齿不清,生产力的巅峰之作,根据斯蒂尔。

我们谈论的轻率的话题是Clojure,它是JVM的一种编程语言,由Rich Hickey于2007年引入。 在2014年的Java One上,Hickey进行了演讲 。 他以以下报价开始

“据我所知,许多最好的程序员和生产力最高的程序员都在用Clojure编写所有内容并对此发誓,然后在很短的时间内制作出可笑的复杂东西。 而且程序员的生产力很重要。”

— Adrian Cockroft,(前)Netflix

Rich的主旨是Clojure使您能够编写更好,更灵活的程序,最重要的是,与使用Java相比,您的工作效率更高。

毫无疑问,这可能就是像Netflix这样的大公司采用Clojure作为Java的更成熟替代方案的原因。 另一个示例是WalmartLabs设置特色图片

“ Clojure将我们的代码库缩减为使用Java编写的代码的五分之一左右”

—沃尔玛实验室设计师Anthony Marcar

到现在为止,该语言已在业界证明了自己。 也许您改用Clojure的充分理由? 我们列出了为您使用Clojure的十个优点。

还请参见: 如何在2020年用Java安全编程

1. Clojure很简单

Rich Hickey毕生致力于设计Clojure。 他认为语言必须很简单。 并不是说它应该是一种简单的语言。 的确,如果Clojure易于学习,它最初可能会赢得某些Java程序员的青睐,但事实并非如此。 确实,通往程序员的启蒙之路绝非易事。 带着所有这些括号,甚至那个愚蠢的前缀符号,也许甚至很痛苦。

但是,一旦您达到了涅rv,您就会发现Clojure的语法实际上非常简单。 简单性的一个例子是编写函数。 Clojure鼓励您编写纯函数-即,不会产生副作用的函数。 Rich Hickey认识到不变性的特性将有助于实现这一目标。 因为如果保证您的变量是不可变的,那么代码就更好地进行推理,并且测试起来也容易得多。

2. Clojure是面向数据的

简单性还源于Clojure不面向对象,而是面向数据的事实。 数据用不可变的哈希映射而不是类表示,就像Java中一样。 这些数据结构易于使用功能进行操作,但它们是相互独立的。 因此,Clojure在哲学上与Alan J. Perlis的以下引用保持一致:

“与在10个数据结构上运行10个功能相比,使100个函数在一种数据结构上运行更好。”

面向对象迫使您不断重新发明轮子,因为这需要您将数据放入类中。 相反,通过Clojure,您可以对所有用例使用相同的有限数据结构集。 此外,OO中的每个新类本身就是一种语言:您必须首先学习其方法,才能访问潜伏的数据结构。 另外,由于Clojure中的地图是不可变的,因此您不必担心副作用。

这是一个小例子。 在Ring(一个用于编写Web应用程序的库)中,处理程序只不过是一个期望哈希图(请求)并返回哈希图(响应)的函数:

(defn what-is-my-ip [request]
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body (:remote-addr request)})

命名空间(此处理程序的作用域)不依赖于Ring库。 我们唯一需要知道的是Ring中的请求应该是什么样的,即我们可能希望在哈希图中使用哪些键,以及应该返回哪些键以产生有效的响应。 在请求和响应之间发生的所有事情无非是带有普通哈希映射的计算。 与使用HttpServletRequestHttpServletResponse ,这无疑简单得多。

3. Clojure需要更少的代码行

使用Clojure时,您不必承担面向对象语言所产生的巨大开销。 这样的开销包括编写接口和实现代码以“保护”您的数据结构。 这意味着与Java代码行相比,您需要更少的Clojure代码行,以实现相同的结果。

您需要编写更少的代码行的另一个原因是因为Clojure是一种功能编程语言。 已知此类语言比命令性编程语言更具表现力。 例如,在Clojure中,您不必为集合上的计算编写循环或迭代。 您要做的就是将高阶函数(例如,映射,过滤和归约)应用于您的集合。

当然,从版本8开始,Java语言已经通过Streams API合并了lambda之类的功能特性和更高阶的功能。 但是还有更多。 由于Clojure是轻率的事实,因此您可以使用来阻止编写样板代码。 这些是在编译时执行的函数,它们接受表达式作为参数。 表达式被表示为数据,您也可以使用Clojure函数进行转换。 所有这些都构成了代码生成,因此您不必自己编写样板代码。

网站TodoBackend包含Todo-list API的几种不同实现。 您也可以使用它来比较语言。 将Clojure实现与Java 7和8进行比较时,会看到以下内容:

  • Clojure:168行Clojure(包括构建配置)
  • Java 7 + Spring MVC:555行XML,228行Java代码,56行Groovy
  • Java 8 + Spring 4 Boot:200行Java,37行Groovy

这里我们没有包括所使用的库和框架中的代码行。 如果我们做到了,我们期望Clojure会有更好的结果。

更少的代码行的优点显而易见:较小的程序包含较少的错误,易于推理,并且-由于其简单性-更加强大。

4. Clojure支持多种平台

Clojure生态系统使您可以在多种环境中重用该语言的知识。 对于服务器端开发,您可以在JVM上使用Clojure(或通过ClojureCLR在.NET中使用)。

对于前端开发,请使用ClojureScript,它可以编译为JavaScript。 ClojureScript编译器可用于在浏览器中运行的程序,也可用于使用NodeJS在服务器端运行的程序。

在保持Clojure实现相互一致方面已付出了很多努力。 它们仅因平台限制而有所不同。 这种限制的一个例子是浏览器中没有多线程。

许多Clojure库都支持Clojure和ClojureScript。 因此,您可以在两个平台上重复使用您的知识。 库开发人员可以使用阅读器条件语句 ,从而可以为所有目标环境使用相同的代码文件。

应用程序开发人员还可以使用阅读器条件语句为所有平台编写一段代码。 例如,以下代码包含一个值为NaN的变量。 在JVM平台('clj')上,它被定义为Double/NaN ,而在JavaScript('cljs')中,它被定义为来自全局名称空间的NaN

(def not-a-number
  #?(:clj Double/NaN
     :cljs    js/NaN
     :default nil))

5. Clojure是交互式的

Clojure是一种交互式编程语言。 通过REPL(read-eval-print循环),您会立即收到反馈。 在开发过程中,即使应用程序正在运行,您也可以重新定义功能并重新测试它们-而无需启动新的编译周期。 不需要诸如JRebel或Quarkus之类的用于热代码重载的工具。

甚至可以跨网络连接到远程REPL会话,以检查生产服务器上应用程序的状态。

ClojureScript还支持REPL会话,该会话使您能够连接到在浏览器(或Node)中运行的代码,因此您可以测试和修改程序。 像Figwheel这样的工具也使您可以立即查看修改后的ClojureScript的结果,而无需刷新浏览器。

所有这些意味着Clojure非常适合实时编码。 使用Clojure,您甚至可以制作现场音乐。 为此,请检查库Overtone

6. Clojure已满堆

一种或另一种方式,Java不是全栈。 它是一种后端语言。 这并不是说人们也没有试图在前端变得有意义。 但是认真地说,谁还在使用AWT,Swing或JavaFX开发应用程序? 同样,Clojure最初被认为是另一种后端语言。 随着ClojureScript的出现以及随后发布的许多前端库和工具的出现,您可以肯定地将Clojure视为完整的堆栈语言。 它还引入了许多有趣的元素,这些元素极大地改善了全栈开发人员的体验。

React

the带JavaScript库React的成功,现在使用ClojureScript构建SPA(单页应用程序)非常容易。 Reagent是一个ClojureScript库,可简化编写React组件的过程。 用于使用Clojure数据结构描述HTML标记的Hiccup语法需要很少的代码行。

这是一个组件示例,该组件计算按钮的点击次数,并随后在div中显示:

Clojure

(def count-state (atom 10))

(defn counter []
  [:div
   @count-state
   [:button {:on-click #(swap! count-state inc)}
    "x"]])

(reagent/render-component [counter]
                          (js/document.getElementById "app"))

使用Om(React的另一个ClojureScript包装器),可以实现比React本身更好的性能 。 这与在ClojureScript(以及Clojure本身)中比较不同状态集的效率更高有关。

7. Clojure防止回调地狱

Javascript开发人员必须解决的问题之一是称为“回调地狱”的现象。 浏览器程序只有一个线程。 这就是为什么我们需要使用嵌套回调的原因。 随着我们应用更深层次的嵌套,代码的可读性将越来越差。

Clojure解决方案由一个核心库core.async组成(您可能已经猜到了),该库简化了异步代码的使用。 不用说,该库在服务器上都可以像在客户端上一样工作。 它的构造块是通道,缓冲区和go块。 Go块是提供同步代码外观的源转换,但最终转换为嵌套的回调。

一个例子。 以下代码首先通过调用REST API来检索用户的电子邮件地址。 为此,使用了http-cljs库,该库将Ajax调用与core.async结合在一起。 作为返回值,我们收到一个通道,可以使用<!读取结果<! (接)操作。 接下来,我们在第二个呼叫中使用电子邮件地址,以获取该用户的订单。

(go (let [email (:body
                 (<! (http/get
                      (str "/api/users/"
                           "123"
                           "/email"))))
          orders (:body
                  (<! (http/get
                       (str
                        "/api/orders-by-email/"
                        email))))]
      (count orders)))

8. Clojure有规格

自2017年底发布Clojure 1.9以来,Clojure附带的spec是一个库,用于描述数据和功能的结构,并支持验证,错误报告,检测和数据生成。 来自Java的开发人员可能会发现Clojure缺少静态类型的问题很难理解。 尽管spec不提供宏语法检查以外的编译时间保证,但它在运行时确实提供了更强大的功能。

一个小例子。 我们可以定义一个规范,该规范表示必须为偶数且大于1000的整数。

(s/def ::big-even (s/and int? even? #(> % 1000)))

我们可以使用工具来检查函数的参数是否符合此规范:

(defn square-big-even
  "returns square of x, which must be a big even integer"
  [x]
  (* x x))

;; define spec for function arguments:
(s/fdef square-big-even :args (s/cat :x ::big-even))

;; instrument
(st/instrument `square-big-even)

(square-big-even 1)
;; => 1 - failed: even? at: [:x] spec: :user/big-even

(square-big-even 2000)
;; => 4000000

来自规范的错误消息似乎有点神秘。 诸如expound之类的库可用于将规范错误数据转换为人类可读的文本。

用于验证的相同规范也可以用于数据生成和生成测试:

(gen/sample (s/gen ::big-even))
;; => (150874 1402248 1562 165164 1146 2300 15226 1564 1686 3298)

9. Clojure是一种很好的脚本语言

在几乎所有软件项目中,都需要编写Shell脚本来自动执行任务。 Java不是最适合脚本语言的语言,因为与流行的选择(例如Bash和Python)相比,Java非常冗长。 它需要一个编译步骤,而JVM的启动时间是另一个障碍。 近年来,为了获得具有良好启动时间的Clojure脚本环境,提出了几种解决方案:

  • 普朗克 :基于ClojureScript和运行在JavaScriptCode
  • 小丑 :Go中实现的Clojure解释器
  • babashka :用Clojure本身编写的Clojure解释器,使用GraalVM本机图像编译

这是一个Babashka脚本,它打印当前目录中所有目录的规范路径。 您可能会注意到java.io.File类是互操作的,它是babashka打包的许多类之一。

#!/usr/bin/env bb

(require '[clojure.java.io :as io])

(defn canonical-dirs [path]
  (->>
   (io/file path)
   (.listFiles)
   (filter #(.isDirectory %))
   (map #(.getCanonicalPath %))))

(doseq [dir (canonical-dirs ".")]
  (println dir))

在我的(Michiel's)Macbook Pro 2019上执行此脚本大约需要19毫秒。

还请参见: JavaScript在RedMonk排名中位居首位,Python与Java并列

10. Clojure是稳定的

与Java一样,Clojure也非常注重API的稳定性。 2009年为Clojure 1.0编写的程序仍可能在2020年与Clojure 1.10.1一起使用。Clojure社区普遍采用Rich Hickey的理念,即API应随着时间的增长而增加(增加功能),放松(要求更少),和错误修复,而不是进行重大更改。 如果您想了解更多关于Spec-ulation的主题演讲( transcript ),请观看。

结语

Java是一种编程语言,已有25年的历史了。 在过去的这些年中,Java的许多替代方案不断出现。 但是自从过去十年的“寒武纪大爆发”以来出现的所有语言中,只有少数达到了成熟:Groovy,Scala以及Clojure。 在本文中,我们列出了一些功能,这些功能可以将Clojure与其他功能完全区分开。 如果您确信,学习Clojure的最佳方法是实际使用它。

翻译自: https://jaxenter.com/clojure-alternative-java-169315.html

clojure java

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值