Java 下一代: Groovy、Scala 和 Clojure 中的共同点(三)

反思异常、表达式和空

在 上一期文章 中,我介绍了 Java 下一代语言用来消除 Java 语言中华而不实的东西和复杂性的创新方式。在这一期 文章中,我将展示这些语言如何消除 Java  的一些瑕疵:异常、语句与表达式,以及围绕 null 的边缘情况。

表达式

Java  语言从 C 语言那里继承的一项传承是区分编程语言 和编程表达式。Java 语句的示例包 括使用 if 或 while 的代码行,以及使用 void 来声明不会返回任何值的方法的代码行。表达式(比如 1 + 2 )用于求取 某一个值。

这种区分在最早的编程语言中就已经开始,比如在 Fortran 中,这种区分基于硬件条件以及对编程语言 设计的初步了解。在许多语言中,它被保留为操作(语句)与求值(表达式)的指示器。但语言设计人员逐渐意识到,该语 言可以完全由表达式组成,在对结果不感兴趣的时候忽略结果。事实上,所有函数式语言完全可以消除这种区分,仅使用表 达式。

Groovy 的 if 和 ?:

在 Java 下一代语言中,传统的命令式语言(Groovy)和函数式语言(Clojure 和 Scala)之间的分离展示了向表达式的进化。Groovy 仍然包含语句,这些语句基于 Java 语法,但添加了更多的表达式 。而 Scala 和 Clojure 则完全使用表达式。

语句和表达式中包含的内容都为语言增添了语法上的笨拙。可以考虑 Groovy 中的 if 语句,它继承自 Java。它有两个版本,清单 1 对它们进行了比较,这两个版本是用于执行判断的 if 语 句,以及神秘的三元运算符 ?::

清单 1. Groovy 的两个 if 语句

def x = 5
def y = 0
if (x % 2 == 0)
  y = x * 2
else
  y = x - 1
println y   // 4

y = x % 2 == 0 ? (x *= 2) : (x -= 1)
println y   // 4

在 if 语句 清单 1 中,我必须将 x 的值设置为一个副作用 (side effect),因为 if 语句没 有返回任何值。要执行判断并同时进行赋值,必须使用三元赋值,如 清单 1 中的第二个赋值语句所示。

Scala 的 基于表达式的 if 语句

Scala 消除了对三元运算符的需求,允许 if 表达式对两种情况都进行处理。您可以使用它 ,就像在 Java 代码中使用 if 语句那样(忽略返回值),或者在赋值语句中使用它,如清单 2 中所示:

清单 2. Scala 的基于表达式的 if 语句

val x = 5
val y = if (x % 2 == 0)
          x * 2
    else
      x - 1
println(y)

Scala 和其他两种 Java 下一代语言一样,不要求方法中包含明确的 return 语句。因此,方法的最 后一行是返回值,强调了这些语言中的方法的基于表达式的特性。

当您在 Java 和 Groovy 代码中进行操作和设置 值时,可以将每个响应封装为一个代码块,如清单 3 中所示,并包含任何所需的副作用:

清单 3. Scala if + 副 作用

val z = if (x % 2 == 0) {
              println("centerisible by 2")
          x * 2
        } else {
              println("not centerisible by 2; odd")
          x - 1
        }
println(z)

在 清单 3 中,除了返回新计算得出的值之外,我还为每种情况打印了一条状态消息。代码块中的代 码行的顺序非常重要:代码块的最后一行表示符合条件的返回值。因此,当您使用基于表达式的 if 进行混合求值和具有副 作用时,必须非常小心。

Clojure 的表达式和副作用

Clojure 也完全由表达式组成,但它更进一步,从求值 代码中区分出了副作用代码。前两个示例的 Clojure 版本是用一个 let 代码块表达的,在清单 4 中,这允许定义局部作 用域变量:

清单 4. Clojure 的基于表达式的 if 语句

(let [x 5
      y (if (= 0 (rem x 2)) (* x 2) (- x 1))]
  (println y))

在 清单 4 中,我为 x 分配了一个值 5,然后使用 if 建立了表达式来计算两个条件:(rem x2 ) 调用了 remainder 函数,类似于 Java % 操作符,并将结果与零值进行比较,在除以 2 时检查零剩余值(zero remainder)。在 Clojure 的 if 表达式中,第一个参数是 condition,第二个参数是 true 分支,第三个参数是可选的 else 分支。if 表达式的结果被分配给 y,然后被打印出来。

Clojure 也允许对每个条件使用代码块(可以包含副 作用),但需要一个包装器,比如 (do ...)。包装器通过使用最后一行作为代码块的返回值,对代码块中的每个表达式 进行求值。清单 5 说明了如何对某个条件或副作用进行求值:

清单 5. Clojure 中的显式副作用

(let 

[x 5
      a (if (= 0 (rem x 2))
          (do
            (println "centerisible by 2")
            (* x 2))
          (do
            (println "not centerisible by 2; odd")
            (- x 1)))]
  (println a))

在 清单 5,我为 if 表达式的返回值分配了 a。对于每个条件,都创建了一个 (do ...) 包装 器,并允许使用任意数量的语句。代码块的最后一行是 (do...) 代码块的返回值,这类似于 清单 3 中的 Scala   示例。请确保目标返回值是最后进行求值的。以这种方式使用 (do...) 代码块是如此之常见,以致于 Clojure 中的许多 结构(比如 (let []))已经包含隐式 (do ...) 代码块,这消除了许多情况下对它们的需求。

Java/Groovy 代 码和 Scala/Clojure 代码中的表达式的比较指示了编程语言中的总趋势,即消除不必要的语句/表达式分歧。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索语言
, java继承问题求解答
, 代码
, 清单
, clojure
, java方法块
, 表达式
, 语句
, java代码求讲解
, 三元一次式
, c语言表达式求值
java中if语句
scala groovy clojure、java scala groovy、groovy clojure、clojure scala、clojure和scala,以便于您获取更多的相关知识。

时间: 2024-10-02 15:37:51

Java 下一代: Groovy、Scala 和 Clojure 中的共同点(三)的相关文章

Java 下一代: Groovy、Scala 和 Clojure 中的共同点(一)

探究这些下一代 JVM 语言如何处理操作符重载 编程语言中的好理念可以延续并扩展到其他语言,就像美酒一样历久弥香.因此,不足奇怪的是,Java 下一代语言 - Groovy.Scala 和 Clojure - 具有很多共同的特性.在本期和下一期 Java 下一代 文章中,我将探讨每种语言语法中功 能清单的一致性.我从能够重载操作符这个特性说起  - 克服了Java 语言中长期存在的一个缺点. 操作符重 载 如果您改造过 Java BigDecimal 类,可能看到过类似于清单 1 的代码: 清单

Java 下一代: Groovy、Scala 和 Clojure 中的共同点(二)

了解Java 下一代语言如何减少样板代码和降低复杂性 Java 编程语言诞生时所面临的限制与如今的开发人员所面临的条件有所不同.具体来讲,由于上世纪 90 年代中期的硬 件的性能和内存限制,Java 语言中存在原语类型.从那时起,Java 语言不断在演化,通过自动装箱(autobox)消除了许 多麻烦操作,而下一代语言(Groovy.Scala 和 Clojure)更进一步,消除了每种语言中的不一致性和冲突. 在这 一期的文章中,我将展示下一代语言如何消除一些常见的 Java 限制,无论是语法上

Java 下一代: 没有继承性的扩展(二)探索 Clojure 协议

"没有继承性的扩展,第 1 部分" 主要讨论了 Goovy.Scala 和 Clojure 中为现有类添加新方法的机制,这也是 Java 下一代语言实现无继承扩展的方法之一.本文将探讨 Clojure 的协议如何以创新的方法拓展 Java 扩展功能,为表达式问题提供出色的解决方案. 尽管这期文章主要关注可扩展性,但也会略为涉及一些允许 Clojure 和 Java 代码无缝互操作的 Clojure 特性.这两种语言有着根本性的差别(Java 是命令式.面向对象的:而 Clojure 是

介绍Java下一代语言Clojure、Scala和Groovy的共同点

在 上一期文章 中,我介绍了 Java 下一代语言用来消除 Java 语言中华而不实的东西和复杂性的创新方式.在这一期文章中,我将展示这些语言如何消除 Java 的一些瑕疵:异常.语句与表达式,以及围绕 http://www.aliyun.com/zixun/aggregation/19527.html">null 的边缘情况. 表达式 Java 语言从 C 语言那里继承的一项传承是区分编程语言 和编程表达式.Java 语句的示例包括使用 if 或 while 的代码行,以及使用 void

了解Groovy、Scala和Clojure如何将行为融入到Java类中

Java 语言的设计有目的地进行了一定的删减,以避免前代产品中已发现的一些问题.例如,Java 语言的设计人员感觉 C++++ 中的多重继承性带来了太多复杂性,所以它们选择不包含该特性.事实上,他们在该语言中很少构建扩展性选项,仅依靠单一继承和接口. 其他语言(包括 Java 下一代语言)存在巨大的扩展潜力.在本期和接下来的两期文章中,我将探索扩展 Java 类而不涉及继承性的途径.在本文中,您会了解如何向现有类添加方法,无论是直接还是通过语法糖 (syntactic sugar). 表达式问题

Groovy、Scala 和 Clojure 如何将行为融入到类中

Java 语言的设计有目的地进行了一定的删减,以避免前代产品中已发现的一些问题.例如,Java 语言的 设计人员感觉 C++ 中的多重继承性带来了太多复杂性,所以它们选择不包含该特性.事实上,他们在该语言 中很少构建扩展性选项,仅依靠单一继承和接口. 其他语言(包括 Java 下一代语言)存在巨大的扩 展潜力.在本期和接下来的两期文章中,我将探索扩展 Java 类而不涉及继承性的途径.在本文中,您会了解 如何向现有类添加方法,无论是直接还是通过语法糖 (syntactic sugar). 表达式

在日益壮大的多语言世界中使用Groovy、Scala和Clojure

在与 Martin Fowler 共同参加的一次主题演讲中,他提供了一个敏锐的观察报告: Java 的遗产是 平台,不是 语言. 最初的 Java 技术工程师曾做过一个了不起的决定,将语言从运行时中分离出来,最终使 200 多种语言可在 Java 平台上运行.该基础架构对平台保持长久活力非常关键,因为计算机编程语言的寿命通常很短.自 2008 年以来,每年由 Oracle 主办的 JVM 语言峰会都会为 JVM 上替代语言的实现者提供与平台工程师公开合作的机会. 欢迎来到 Java 下一代专栏系

Groovy、Scala 和 Clojure的使用

在与 Martin Fowler 共同参加的一次主题演讲中,他提供了一个敏锐的观察报告: Java 的遗产是 平台,不是 语言. 最初的 Java 技术工程师曾做过一个了不起的决定,将语言从运行时中分离出来,最终使 200 多种语言可在 Java 平台 上运行.该基础架构对平台保持长久活力非常关键,因为计算机编程语言的寿命通常很短.自 2008 年以来,每年由 Oracle 主办的 JVM 语言峰会都会为 JVM 上替代语言的实现者提供与平台工程师公开合作的机会.   欢迎来 到 Java 下一

Groovy、Scala和Clojure共享的函数结构及其优势

本期文章将展示常见的函数式编程结构在 Java 下一代语言中的表示方式,指出那些功能在实现细节上的一些细微差别. 当垃圾回收成为主流时,它消除了所有类别的难以调试的问题,使运行时能够为开发http://www.aliyun.com/zixun/aggregation/7187.html">人员管理复杂的.容易出错的进程.函数式编程旨在为您编写的算法实现同样的优化,这样您就可以从一个更高的抽象层面开展工作,同时运行时执行复杂的优化. Java 下一代语言并不都占用从命令式到函数式的语言频谱的