我完全可以理解为什么Clojure非常适合并发编程。我也可以看到FP在这方面的优势。
但显然,并非我们编写的每一行代码都是线程的一部分或需要并发访问。对于代码的那些部分(更简单和连续的代码片段),Java真正错过了Clojure提供的内容是什么?
在Java中是否真的错过了Multimethods,Dynamic binding,Destructuring bind等功能?
我认为我的问题也可以被描述为:
答案 0 :(得分:25)
在Java中是否真的错过了Multimethods,Dynamic binding,Destructuring bind等功能?
是。也...
一流的功能。美味的一流功能。这不仅仅是FP的事情。人们迫切要求Java 7中的闭包。
码是数据。这是任何Lisp的好处。 Lisp代码不仅仅是您在编译器口中提供的文本blob,而且永远不会再看到它,它是可以通过编程方式操作的列表和向量以及符号和文字的结构。这导致了强大的宏和一流的符号以及许多其他好东西。它导致了一种高度可扩展和强大的语言。
Clojure具有更好的控制和循环结构,能够通过宏和一流函数创建自己的构造。 Java有for
和foreach
以及while
(多年来甚至没有foreach
)。 Clojure有map
,filter
,reduce
,mapcat
,许多do
表单,大量if
和when
表单,列表推导通过for
,等等。如果这些不存在,您可以自己编写。在Java中,您需要等待十年才能成为一个委员会(也许)批准这些功能。
减去那些处理静态类型的人,为Java 7设置的所有功能,Clojure已经拥有或可能具有琐碎的功能。 “自动资源管理”,Clojure有with-open
。 “对集合的语言支持”,Clojure(以及Ruby,Perl,Python ......)已经有了。 “切换中的字符串”,Clojure具有更强大的类似案例的构造,如condp
,以及您能想到的任何其他内容。你可以在十几行Clojure中自己写这些。
列表,地图,数组,集合,有序集,有序映射等的简明语法以及几乎可互换的使用都归功于seq
抽象。对正则表达式,字符,匿名函数等的字面支持
Java有强制检查的异常,这很烦人; Clojure没有。
Java语法冗长且不规则。 Clojure语法简洁而有规律。由于像->
和doto
之类的宏,以及像proxy
和(很快)reify
这样的构造,即使用Clojure编写的Java通常也比用Java编写的Java更简洁。
Java代码有太多强制性的样板和无休止的重复。 public static void main(String[] args){...}
等等.Clojure几乎没有这个样板,而在表现力或力量方面几乎没有牺牲。即使是今天其他静态类型的语言似乎也在采用类型推理的方式。你需要一个庞大的以Java为中心的IDE来编写并无休止地“重构”Java代码,这是有充分理由的。用手写它会让你发疯,并用手指捏住小块。
在Java中,一切都是类或接口,无论是否应该是,这都是不必要的复杂性的原因。有许多程序必须被忽视以适应OOP风格。 Clojure让你避免这种情况。 A nice rant to this effect. Clojure主要关注动词。
通过REPL进行交互式编程很有趣。编译/运行/调试周期不是。如果你想要的话,Clojure仍会编译成.class文件;在此期间,您可以坐在代码中间,在运行时自由修补。
Clojure的元数据和理智的平等测试很愉快。正如它自动推广int到long到Bigint,本地处理有理数,等等。
动态类型导致更短,更通用,因此更可重用,因此比静态类型更强大的代码。 (这显然是一个备受争议的问题,所以我把它放在最后。)
Scala和Groovy以及JRuby和Jython以及其他JVM语言的流行 - 这不是Java应该被视为一个很好的迹象,虽然JVM很好,但Java语言对许多人来说都是令人不快的人
答案 1 :(得分:7)
布莱恩已经很好地总结了它。这是给我留下深刻印象的东西。 (摘自Stuart Halloway的书Programming Clojure)
来自Apache Commons的Java代码:
public class StringUtils {
public static boolean isBlank(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(str.charAt(i)) == false)) {
return false;
}
}
return true;
}
}
以下是Clojure中的类似实现:
(defn blank? [s] (every? #(Character/isWhitespace %) s))
答案 2 :(得分:2)
对于一个人而言,在Clojure中通常会有很少的“仪式”。像Python和Ruby这样的语言也比Java更具优势(因此JRuby,Jython的流行)。
但请注意,尽管可能存在明确的模式,但有时Java中无法避免冗长。 Clojure的宏在这里是一个巨大的胜利 - 甚至超过其他类似的动态语言。
另一件需要考虑的事情是Clojure程序往往是并发安全的。因此,如果您决定将特定应用程序并发,那就不会太痛苦。如果不事先做出很多决定,使用Java将会更加困难。
还想知道如果Clojure缺乏强大的并发性原语,而且不变性就像是说“如果Clojure不是Clojure会怎么样?”,那么Clojure是否会比Java有明显优势。