当前位置: 首页 > news >正文

长沙建站智能模板58同城宿迁二手房

长沙建站智能模板,58同城宿迁二手房,江西省住房和城乡建设厅网站,scratch少儿编程网站Java 语言是否应增加闭包以及如何添加#xff1f;在跨越边界 系列最近的一篇文章中#xff0c;我的朋友兼同事 Bruce Tate 以 Ruby 为例描述了闭包的强大功能。最近在安特卫普召开的 JavaPolis 会议上#xff0c;听众人数最多的演讲是 Neal Gafter 的 “向 Java 语言增加闭包…Java 语言是否应增加闭包以及如何添加在跨越边界 系列最近的一篇文章中我的朋友兼同事 Bruce Tate 以 Ruby 为例描述了闭包的强大功能。最近在安特卫普召开的 JavaPolis 会议上听众人数最多的演讲是 Neal Gafter 的 “向 Java 语言增加闭包特性”。在 JavaPolis 的公告栏上与会者可以写下和 Java 技术有关(或者无关)的想法其中将近一半和关于闭包的争论有关。最近似乎 Java 社区的每个人都在讨论闭包——虽然闭包这一业已成熟的概念早在 Java 语言出现的 20 年之前就已经存在了。本文中我的目标是介绍关于 Java 语言闭包特性的种种观点。本文首先介绍闭包的概念及其应用然后简要说明目前提出来的相互竞争的一些方案。闭包基本概念闭包是可以包含自由(未绑定)变量的代码块这些变量不是在这个代码块或者任何全局上下文中定义的而是在定义代码块的环境中定义。“闭包” 一词来源于以下两者的结合要执行的代码块(由于自由变量的存在相关变量引用没有释放)和为自由变量提供绑定的计算环境(作用域)。在 Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和 Python 等语言中都能找到对闭包不同程度的支持。闭包的价值在于可以作为函数对象 或者匿名函数对于类型系统而言这就意味着不仅要表示数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象就是说这些函数可以存储到变量中、作为参数传递给其他函数最重要的是能够被函数动态地创建和返回。比如下面清单 1 所示的 Scheme 例子(摘自 SICP 3.3.3)清单 1. Scheme 编程语言的函数示例该函数接受另一个函数作为参数并返回缓存后的函数(define (memoize f) (let ((table (make-table))) (lambda (x) (let ((previously-computed-result (lookup x table))) (if (not (null? previously-computed-result)) previously-computed-result (let ((result (f x))) (insert! x result table) result))))))上述代码定义了一个叫做 memoize 的函数接受函数 f 作为其参数返回和 f 计算结果相同的另一个函数不过新函数将以前的计算结果保存在表中这样读取结果更快。返回的函数使用 lambda 结构创建该结构动态创建新的函数对象。斜体显示的标识符在新定义函数中是自由的它们的值在创建该函数的环境中绑定。比如用于存储缓存数据的表变量在调用 memoize 的时候创建由于被新建的函数引用因此直到垃圾回收器回收结果函数的时候才会被收回。如果调用结果函数时带有参数 x 它首先检查是否已经计算过 f(x)。是的话返回已经得到的 f(x)否则计算 f(x) 并在返回之前保存到表中以备后用。闭包为创建和操纵参数化的计算提供了一种紧凑、自然的方式。可以认为支持闭包就是提供将 “代码块” 作为第一级对象处理的能力能够传递、调用和动态创建新的代码块。要完全支持闭包这种语言必须支持在运行时操纵、调用和创建函数还要支持函数可以捕获创建这些函数的环境。很多语言仅提供了这些特性的一个子集具备闭包的部分但不是全部优势。关于是否要在 Java 语言中增加闭包关键问题在于提高表达能力所带来的益处能否与更高的复杂性所带来的代价相抵消。匿名类和函数指针C 语言提供了函数指针允许将函数作为参数传递给其他函数。但是C 中的函数不能有自由变量所有变量在编译时必须是已知的这就降低了函数指针作为一种抽象机制的表达能力。Java 语言提供了内部类可以包含对封闭对象字段的引用。该特性比函数指针更强大因为它允许内部类实例保持对创建它的环境的引用。乍看起来内部类似乎确实提供了闭包的大部分作用虽然这还不是全部作用。您可以很容易构造一个名为 UnaryFunction 的接口并创建能够缓存任何 unary 函数的缓存包装程序。但是这种方法通常不易于实现它要求与函数交互的所有代码在编写时都必须知道这个函数的 “框架”。闭包作为一种模式模板匿名类允许创建这样的对象该对象能够捕获定义它们的一部分环境但是对象和代码块不一样。以一个常见的编码模式为例如执行带有 Lock 的代码块。如果需要递增带有 Lock 的计数器代码如清单 2 所示——即使这么简单的操作也非常罗嗦清单 2. 执行加锁代码块的规范用法lock.lock();try { counter;}finally { lock.unlock();}如果能够提取出加锁管理代码就好了这样会使代码看起来更紧凑也不容易出错。首先可以创建如清单 3 所示的 withLock() 方法清单 3. 提取了 “加锁执行” 的概念但是问题在于缺乏异常的透明性public static void withLock(Lock lock, Runnable r) { lock.lock(); try { r.run(); } finally { lock.unlock(); }}不幸的是这种方法只能达到您预期的部分目标。创建这种抽象代码的目标之一是使代码更紧凑但是匿名内部类的语法不是很紧凑调用代码看起来如清单 4 所示清单 4. 清单 3 中 withLock() 方法的客户端代码withLock(lock, new Runnable() { public void run() { counter; }});要递增一个加锁的计数器仍然需要编写很多代码另外将受到锁保护的代码块转化成方法调用所带来的抽象问题大大增加了问题的复杂性——如果受保护的代码块抛出一个检测异常怎么办现在我们不能使用 Runnable 来表示执行的任务而必须创建一种新的表示方法以允许在方法调用中抛出异常。不幸的是在这里泛化也帮不上多少忙虽然方法可以用泛型参数 E 表示可能抛出的检测异常但是这种方法不能很好地泛化抛出多种检测异常类型的方法(这就是为何 Callable 中的 call() 方法声明为抛出 Exception 而不是用类型参数指定一个类型的原因)。清单 3 中的方法最大的问题在于缺乏异常透明性除此之外还存在其他非透明性的问题在 清单 4 的 Runnable 上下文中return 或 break 这类语句的含义与 清单 2 中 try 语句块中的一般意义不同。理想情况下受保护的递增操作应该像清单 5 所示的那样并且块中代码的含义和 清单 2 的扩展形式相同清单 5. 清单 3 客户端代码的理想形式(但是是假设形式)withLock(lock, { counter; });在语言中添加闭包以后就可以创建行为类似控制流结构的方法比如 “加锁执行这段代码”、“操作流并在完成后将其关闭” 或者 “为代码块的执行计时” 等。这种策略有可能简化某些类型的代码这些代码反复使用特定编码模式或者惯用法比如 清单 2 所示的加锁用法。(在一定程度上提供类似表达能力的另一种技术是 C 预处理器它可以将 withLock() 操作用预处理宏表示虽然和闭包相比宏更难以组织而且安全性也更差。)泛化算法的闭包闭包能够大大简化代码的另一个地方是泛化算法的使用。随着多处理器计算机越来越便宜利用小粒度并行机制的重要性日渐突出。使用泛化算法定义计算为库实现在问题空间中采用并行机制提供了一种自然的方式。比方说假设要计算一个大型数字集合的平方和。清单 6 给出了一种计算方法但这种方法是按顺序计算结果的对于大规模多处理器系统可能不是效率最高的方法清单 6. 顺序计算平方和double sum;for (Double d : myBigCollection) sum d*d;每次循环迭代有两个操作取平方累加到最终结果。平方操作是互相独立的可以并行执行加法操作也不一定要执行 N 次如果计算组织得当只要 log(N) 次操作即可完成。清单 6 中的操作是 map-reduce 算法的一个示例对大批数据元素中的每一个数据元素应用一个函数然后将每次应用该函数计算出的结果通过某种累加函数累加起来。假设有一个 map-reduce 实现过程接受数据集作为输入用一元函数处理每个元素用二元函数累加结果则可用清单 7 所示的代码完成平方和运算清单 7. 使用 MapReduce 计算平方和可以实现并行执行Double sumOfSquares mapReduce(myBigCollection, new UnaryFunction { public Double apply(Double x) { return x * x; } }, new BinaryFunction { public Double apply(Double x, Double y) { return x y; } });假设清单 7 中的 mapReduce() 实现知道哪些操作可以并行执行因而可以将函数应用和累加过程并行执行从而改进并行系统的吞吐量。但是清单 7 中的代码不简洁用了更多代码来表达和清单 6 中三行代码等价的泛化算法。通过闭包可以更好地管理清单 7 中的代码。比如清单 8 中的闭包语法和目前提出的 Java 语言闭包方案都不一样目的仅在于说明闭包对泛化算法的支持清单 8. 使用 MapReduce 和假设的闭包语法计算平方和sumOfSquares mapReduce(myBigCollection, function(x) {x * x}, function(x, y) {x y});清单 8 中基于闭包的算法具有两方面的好处代码容易阅读和编写抽象层次比顺序循环更高能够有效地通过库实现并行。闭包方案目前至少提出了两种向 Java 语言增加闭包的方案。其一绰号为 “BGGA”(名字源于其作者 Gilad Bracha、Neal Gafter、James Gosling 和 Peter von der Ahe)它扩展了类型系统引入了 function 类型。其二绰号为 “CICE” (代表 Concise Inner Class Expressions简洁内部类表示)是由 Joshua Bloch、Doug Lea 和 “疯狂的” Bob Lee 所支持的其目标更谦虚简化匿名内部类实例的创建。 JSR 可能很快就会收到这方面的提议考虑在未来的 Java 语言版本中支持闭包的形式和程度。BGGA 方案BGGA 方案提出了 function 类型的概念即函数都带有一个类型参数列表、返回类型和 throws 子句。在 BGGA 方案中计算平方和的代码将如清单 9 所示清单 9. 使用 BGGA 闭包语法计算平方和sumOfSquares mapReduce(myBigCollection, { Double x x * x }, { Double x, Double y x y }); 字符到左侧花括号之间的代码表示参数的名称和类型右侧的代码表示定义的匿名函数的实现。这段代码可以引用块中定义的局部变量、闭包的参数以及创建闭包的作用域中的变量。在 BGGA 方案中可以声明 function 类型的变量、方法参数和方法返回值。在需要一个抽象方法类(如 Runnable 或 Callable)实例的任何上下文中都可以使用闭包对于匿名类型的闭包您可以使用带有给定参数列表的 invoke() 方法来调用。BGGA 方案的主要目标之一是允许程序员创建行为类似控制结构的方法。因此BGGA 还在语法上提出了一些吸引人的花招允许像新的关键字那样调用接受闭包的方法从而能够创建像 withLock() 或 forEach() 这样的方法然后向控制原语一样调用它们。清单 10 说明了根据 BGGA 方案如何定义 withLock() 方法清单 11 和 清单 12 说明了如何调用该方法包括标准形式和“控制结构”形式清单 10. 采用 BGGA 闭包方案编写的 withLock() 方法public static T withLock(Lock lock, {T throws E} block) throws E { lock.lock(); try { return block.invoke(); } finally { lock.unlock(); }}清单 10 中的 withLock() 方法接受锁和闭包。闭包的返回类型和 throws 子句是泛化参数编译器中的类型推断通常允许在未指定 T 和 E 值的情况下调用如清单 11 和 12 所示清单 11. 调用 withLock()withLock(lock, { System.out.println(hello);});清单 12. 使用控制结构的缩写形式调用 withLock()withLock(lock) { System.out.println(hello);}和泛化一样BGGA 方案中闭包的复杂性在很大程度上是由库的编写者来分担的使用接受闭包的库方法更简单。使用内部类实例是闭包所带来的好处但是这种方法缺少透明性BGGA 方案在一定程度上还有助于解决这个问题。比如return、 break 和 this 在某一代码块中的语义与其在 Runnable(或其他内部类实例)中同一代码块中的语义是不同的。为了利用泛化算法而对代码进行移值的时候这些不透明因素可能会造成混乱。CICE 方案CICE 方案要简单得多它解决了实例化内部类实例不太灵活的问题。它没有建立函数类型的概念只不过为一个抽象方法(如 Runnable、Callable 或 Comparator)内部类实例化提出了一种更紧凑的语法。清单 13 说明了按照 CICE 如何计算平方和。它显示使用了 mapReduce() 中的 UnaryFunction 和 BinaryFunction 类型。mapReduce() 的参数是从 UnaryFunction 和 BinaryFunction 派生的匿名类这种语法大大了降低了创建匿名实例的冗余。清单 13. 采用 CICE 闭包方案计算平方和的代码Double sumOfSquares mapReduce(myBigCollection, UnaryFunction(Double x) { return x*x; }, BinaryFunction(Double x, Double y) { return xy; });由于为传递给 mapReduce() 的函数所创建的对象是普通的匿名类实例其函数体可以引用封闭域中定义的变量清单 13 中的方法和清单 7 相比唯一的区别在于语法的繁简程度。结束语BGGA 方案为 Java 这种语言增加了功能强大的新武器但是同时也为其语义和语法带来了可以预见的复杂性。另一方面CICE 方案更简单利用语言中已有的特性并使其更易于使用但是没有增加重要的新功能。闭包是一种强大的抽象机制用过之后多数人不愿意放弃。(问问那些熟悉 Scheme、Smalltalk 或 Ruby 编程的朋友对闭包的感想如何他们可能会反问您对呼吸有什么感想。)但语言是有机的整体为语言增加最初设计时没有预料到的新特性充满了危险而且会增加语言的复杂性。争论的焦点不在于闭包是否有用——因为答案显然是肯定的——而在于为闭包重新改造 Java 语言的好处是否抵得上要付出的代价。
http://www.sadfv.cn/news/409171/

相关文章:

  • 河北省建设厅管网站wordpress风格
  • 网站优化模板青岛做网站哪家专业
  • 网站建设教程txt新网互联 网站上传
  • 网站后台做数据库备份代码网站快速排名技术
  • 南昌企业网站建设费用量个网站一个域名
  • 秦皇岛庆云网站建设基金公司网站建设方案
  • 网站开发ide深圳外贸公司倒闭
  • 模拟百度搜索词进入网站长春880元网站建设
  • jsp网站开发什么框架科技让生活更美好500字六年级
  • 签订网站制作合同注意事项宁夏企业网站建设
  • 东莞网站模板小程序与app
  • 网站开发记科目洛阳制作网站公司吗
  • 百度云做网站空间WordPress侧滑手机菜单
  • 做网站公司关键词张江网站建设
  • 精神文明地方联盟网站建设asp官方网站
  • 上海网站建设托管新冠最新本土病例
  • 临沂网站优化公司网站建设公司中企动力强
  • 营销型网站工程长沙网站优化外包
  • 哪个网站做3d模型个人网站内容如何填写
  • asp 网站源代码表格制作软件app
  • 网站建设费计入什么科目比较好贫困户房屋建设补助在哪个网站公布
  • 定制网站和模板建站哪个好用php做的网站模版
  • 网站建设后压缩代码网站谁做的比较好看
  • 佛山网站建设冯哥做淘客网站 名字
  • 如何自己做的网站旅游网页设计页面模板
  • 个人网站开发项目总结上海网站平台建设
  • 免费北京网站建设wordpress 统计流量
  • 佛山做网站3lue湖南省城乡和住房建设厅网站
  • 重庆付费网站推广网站建设明细价单
  • 建南沙做网站公司珠珠宝宝网网站站建建设设