- 浏览: 5164135 次
- 性别:
- 来自: 天津
博客专栏
-
实战 Groovy
浏览量:29320
文章分类
- 全部博客 (639)
- 代码之谜 (6)
- JavaScript quirks (5)
- 程序员 (92)
- Java (93)
- BT编程 (7)
- html/css (64)
- Groovy&Grails (42)
- Android (20)
- C/C++ (5)
- PHP/Perl/Python (46)
- 经典文章 (51)
- CodeIgniter (14)
- JQuery (10)
- 笑话 (4)
- 其他 (32)
- javascript (69)
- 云计算 (0)
- html5 (7)
- 面试 (8)
- google (3)
- nosql (2)
- nodejs (11)
- go (5)
- erlang (1)
- 小常识 (3)
- 冷知识 (5)
- database (4)
- web (12)
- 架构 (12)
- Exception (0)
最新评论
-
jqw1992:
https://www.chromefor.com/libra ...
[福利] 开发者必备的 Chrome 插件——ChromeSnifferPlus -
litjerk:
初步算了一下,目前最最精简的Win98版是5M,他5个小时多敲 ...
让人目瞪口呆的三位世界级电脑大师 -
379855529:
。。似乎重点没说NIO啊,前面基础只是铺垫的很好的,可是我要的 ...
Java NIO与IO的详细区别(通俗篇) -
springmvc_springjpa:
spring mvc demo教程源代码下载,地址:http: ...
一步步开发 Spring MVC 应用 -
匡建武:
Good
四个程序员的一天
Java的闭包(Closure)特征最近成为了一个热门话题。 一些精英正在起草一份议案,要在Java将来的版本中加入闭包特征。 然而,提议中的闭包语法以及语言上的这种扩充受到了众多Java程序员的猛烈抨击。
不久前,出版过数十本编程书籍的大作家Elliotte Rusty Harold发表了对Java中闭包的价值的质疑。 尤其是他问道“for 循环为何可恨?”[http://justjavac.com/other/2012/05/15/whats-wrong-with-the-for-loop.html]:
我不知道,有些人这么着急的要把 for 循环消灭掉,他们反对的究竟是什么? 这已经不是第一次或第二次计算机学界的理论家们起来反对 for 循环(或类似的东西)了。
如果只说Elliotte质疑不起眼的闭包的价值,这是不公平的。 他主要抱怨是,在读了另一位著名人物、获得过Jolt 大奖并创造过最高销售记录的《Better, Faster, Lighter Java》的 作者Bruce Tate的最近的关于此主题的专题后, 他看不出闭包在Java中有什么价值。
(Bruce用Ruby做的例证):
表 1. 最简单的闭包
3.times {puts "Inside the times method."}
结果:
Inside the times method.
Inside the times method.
Inside the times method.
times是3这个对象上的一个方法。 它把闭包中的代码执行了3次。{puts "Inside the times method."}
是闭包。 它是一个匿名函数,把它传入times方法,打印出静态句子。 相比起传统的for循环语句,这样的代码显得更紧凑,更简单,如表2中所示:
表 2: 非闭包的循环
for i in 1..3
puts "Inside the times method."
end
由于这种毫无生气的对闭包的介绍,我也很难看出它的真正价值。 这首个比较,充其量也就能体现出一种微妙的差别。 Bruce在developerWorks上的文章里的其它的例子也大多是价值不大的,要么含糊不清,要么缺乏启发意义。
对于这种Ruby风格的闭包给Elliotte带来的困惑,我不打算进一步评论; 对这种问题过于挑剔毫无意义。
我也不想讨论目前的关于Java中的闭包的语法的提议的争论,包括Java中是否应该有闭包这样的大问题。 在这样的争论中我没有立场,说实话,我是不在乎这些问题如何或何时被解决。
虽然如此,Elliotte却提出了一个重要的问题:for 循环为什么可恨?
下面是一个常见的例子:
double sum = 0;
for (int i = 0; i < array.length; i++) {
sum += array[i];
}
这有什么问题? 我编了很多年的程序,我对这种语法一眼扫过去很舒服;很显然,它是把一个数组里的值加到一起。
但当去真正的阅读这段代码时,这四行代码里大概散布着30多个标记符号需要我去分析处理。 不错,有些字符可以通过语法简写方式来缩减。 但为了这样一个简单的加法,你需要写出一堆东西,还要保证写的正确。
凭什么这样说?下面是Elliotte的文章里另外一个例子,原文拷贝:
String s = "";
for (int i = 0; i < args.length; i++) {
s += array[i];
}
看见了里面的错误吗? 如果这代码编译通过,并通过的代码审查,你可能需要数周才会发现这样的bug,再数周才能制作出补丁。 这些只是简单的for循环。
想象一下,当for循环体变得越来越大,甚至有嵌套时,事情会变得多么的复杂。 (如果你仍旧不担心这样的bug,认为这只是拼写错误,那么你就想想有多少次在for循环里你是这样的。)
如果你能够把一个简单的for循环写成一行,带有更少的重复和更少的字符,这样不仅更容易阅读,也更容易书写。 因为这样更简洁,引入bug的机会就更少,当bug出现时,也更容易被发现。
那闭包对此有何帮助?下面是第一个例子,用Haskell语言写成的:
total = sum array
哈哈,我是在说谎。sum函数并没有使用闭包。 它是按照fold的方式定义的,而fold是接受闭包的:
total = foldl (+) 0 array
下面是第二个例子,很常见,而且使用了闭包:
s = concat array
s = foldr (++) [] array
我承认,使用这些叫做foldl 和 foldr 样子古怪的函数来解释闭包的作用,这对那些更熟悉for循环的程序员来说没有多大意义。 但是,这几个函数却能突出for循环的关键弊端:它把三种独立不同的操作合并到一起了——过滤,归纳和转换。
上面的这两种for循环,它们的目标是接收一个数值列表,把它们归纳成一个值。 函数式编程的程序员称这些操作为“folds(合并)”。
一个fold运算的过程是,首先要有一个操作(一个闭包)和一个种子值,还有使用list里的第一个元素。 这个操作被施加到种子值和list里的第一个元素上,产生出一个新的种子值。 fold运算然后把这个操作运用到新种子值和list里的下一个元素上,一直这样,直到最后一个值,最后一次操作的结果成为fold运算的结果。
下面是一个演示:
s = foldl (+) 0 [1, 2, 3]
= foldl (+) (0 + 1) [2, 3]
= foldl (+) 1 [2, 3]
= foldl (+) (1 + 2) [3]
= foldl (+) 3 [3]
= foldl (+) (3 + 3) []
= foldl (+) 6 []
= 6
Haskell语言里提供了很多fold函数;foldl函数从list的第一位开始运算,依次反复到最后一个,而foldr函数,它从list的最后一个函数开始运算,从后往前。 还有很多其它相似的函数,但这两个是最基本的。
当然,folds是一些非常基本的运算,如果抛弃for循环而以各种形式的foldl 和 foldr 咒符来替换,你会很困惑。
事实上,更高级的操作,例如sum, prod 和 concat都是以各种folds定义的。 当你的代码以这种高级的归纳操作运算来编写时,代码会变得更简洁,更易读,更易写,更易懂。
当然,并不是所有的for循环都是归纳操作。看看下面这个:
for (int i = 0; i < array.length; i++) {
array[i] *= 2;
}
这是一个转换操作,函数式编程的程序员称之为map操作:
new_array = map (*2) array
map函数的工作方式是,它会检查list里的每个元素,将一个函数应用到每个元素上,形成一个新的list,里面是新的元素。 (有些语言里的这种操作是原位替换)。 这是一个很容易理解的操作。sort函数的功能相似,它接受一个list,返回(或修改)一个list。
第三种类型的for循环是过滤。
下面是个例子。
int tmp[] = new int[nums.length];
int j = 0;
for (int i = 0; i < nums.length; i++) {
if ((nums[i] % 2) == 1) {
tmp[j] = nums[i];
j++;
}
}
这是一个非常简单的操作,但使用了for循环和两个独立的计数器后,毫无必要的复杂表现把事实真相完全掩盖了。 如果过滤是一种基本的操作,它应该像一个fold或一个map那样,而事实上,它是的:
odds = filter (\i => (i `mod` 2) == 1) nums
odds = filter isOdd nums -- 更常用的形式
从核心上讲,这就是为什么for循环有问题:它把(至少)三种独立的操作合并到了一起, 但重点却关注了一个次要细节问题:遍历一系列的值。
而事实上,fold,map 和 filter是处理一个数据list的三种不同的操作,它们应该被分别处理。 采用把闭包传入循环内的方式,我们能更容易的把what 从 how 中分离出来。 每次遍历一个list时我都会使用一个匿名函数,或复用通用的函数(例如 isOdd, (+) 或 sqrt)。
虽然闭包并不是一个很深奥的概念,但当它深深的烙进了一种语言和它的标准库中时,我们不需要使用这些低级的操作搞的代码混乱不堪。 相反,我们可以创建更高级的运算,做我们想要的事,比如sum 和 prod。
更重要的,以这些概念思考问题会使我们更容易思考更复杂的操作,比如变换一个tree,过滤一个vector,或把一个list合并成一个hash。
在最后,Elliotte还提到了一些关于在多核处理器上并行执行的问题,说像3.times 这样的代码会比 for 循环效率“差”。
不幸的是,我想他没说到点上。不错,有一些运算需要序列化,有一些可以并行。 但是如果你只基于一个for循环,很难判断出哪些归为哪类,这是一个复杂的编译器优化问题。 如果你把一个可能进行并行运算的操作(例如map 和 filter)分解成连续的运算(例如foldl 和 foldr),编译器更容易从中做出判断。
不仅如此,如果你比编译器更了解你的数据,你可以显式的要求一个map操作被顺序执行或并行执行。
本文英文原文链接:What’s Wrong with the For Loop
发表评论
-
Java NIO与IO的详细区别(通俗篇)
2014-01-02 10:51 69420内核空间、用户空间 ... -
Java EE 单元测试
2013-09-12 10:56 4776觉得测试 Java EE 应用程序太困难、不方便或者太复杂? ... -
JUnit 测试建议
2013-07-22 09:04 3480以下是对JUnit实践的一 ... -
老生常谈:面试算法有必要吗?
2013-04-01 09:55 32753声明:虽然发表在愚人节,但是文章内容很严肃。 前几天在知 ... -
一步步开发 Spring MVC 应用
2013-02-23 10:53 10349Spring MVC 框架 Spring 框 ... -
「译」Java集合框架系列教程四:Set接口
2013-01-18 13:20 2527原文:The Set Interface 译文:Java集 ... -
「译」Java集合框架系列教程三:Collection接口
2013-01-18 13:16 2369原文:The Collection Interface 译 ... -
「译」Java集合框架系列教程二:集合接口
2013-01-18 13:13 2010原文:http://docs.oracle.c ... -
Java集合框架系列教程一:集合框架简介
2013-01-18 12:47 3028原文:http://docs.oracle.com/jav ... -
Java泛型-类型擦除
2012-12-05 15:48 14615一、概述 Java泛型在使用过程有诸多的 ... -
千万不要把 bool 当成函数参数
2012-11-16 08:33 12488我们有很多 Coding Style 或 代码规范。 但这一条 ... -
网站建设中关于eclipse启动参数的优化
2012-08-23 09:23 2501在网站建设中,经常用 ... -
Eclipse程序员要掌握的常用快捷键
2012-08-22 09:33 10059判断一个人的编程水平,就看他用键盘多,还是鼠标多。用键 ... -
java中equals和==的区别
2012-08-15 16:31 2029值类型是存储在内存中的堆栈(简称栈),而引用类型的变量在 ... -
名词王国里的死刑(翻译) - A Story of Hello World
2012-07-23 10:43 11811翻译自Steve Yegge的大 ... -
好代码是廉价的代码
2012-07-19 08:03 3295长久以来我一直主张:好代码是廉价的代码。 当我跟做开发 ... -
只要一个返回语句
2012-05-18 13:18 1819别再这样写了: publ ... -
java编程的78条黄金法则
2012-05-16 12:57 2358创建和销毁对象 1、考虑用静态工厂方法(返回类的实例的 ... -
Java 8 新功能
2012-05-02 08:48 1900我们已经急不可待想知道Java 8可用的新功能,其中大部 ... -
java面试题及答案(二)
2012-04-25 13:01 247216、同步和异步有何异 ...
相关推荐
[解析]FOR循环为何可恨?.pdf
家长为了让孩子能在竞争激烈的环境中脱颖而出,不惜一切代价为孩子挑选名校,认为只有这样,才能确保孩子进入好的高中、大学,从而拥有更好的未来。一位受访的母亲直言,如果孩子不能进入优质学校,可能会影响他们...
这篇文档实际上是一篇小学四年级学生的作文,名为《可爱又可恨的蝈蝈》。文章主要描述了作者对蝈蝈这种昆虫的观察和感受,同时展现了蝈蝈的外貌特征、生活习性和食性。 首先,作者描绘了蝈蝈的外观特征。蝈蝈的身体...
这篇文档是一个针对三年级学生的科学教案,主题是"可爱又可恨的风",旨在让学生了解风的特点、利用方式以及可能带来的危害,并引导他们思考如何与风和平共处。以下是教案中的关键知识点: 1. **风的特点**:风是...
在当前中国PCB产业所面临的市场环境下,存在多方面的挑战和机遇,特别在汽车电子和新能源汽车的发展上表现得尤为突出。 首先,PCB产业链中的企业正在经历原材料价格的普遍上涨,如煤炭、铁矿石和造纸等大宗商品价格...
亲测有效,想到自己下载的时候每个都要好多积分才能下,可恨自己没有积分,就好气,分享给大家。本想免费给大家,但资源分数没有0这个选项,大家就意思意思下吧,也当给自己攒点积分。如果你们真的没有积分的话,就...
他在寻找眼镜时可能想了什么?为何找不到?当女儿递回眼镜,他为何道谢?如果他知道是女儿,又会如何反应?女儿的回应又是什么?这样的互动不仅加深了学生对课文的理解,也锻炼了他们的想象力。 第二课时进一步深入...
很多软件工程师或者坐办公室的...网上也有很多类似的闹钟,但经常发现这些免费的软件内多数藏有病毒, 不注意间,自己用了10年的QQ丢了, 并且可恨的是,偷盗者还联系我的QQ好友,打着我的名义向他们骗钱。。。可恨啊!
这是我用jquery框架编写的一个可以使用你的网站中的所有PNG格式的图片支持透明度,本来符合W3C规范的浏览器是支持PNG透明的,但是可恨的是IE5和IE6都不支持,甚至IE7有时候还会出现错误,不过通过我的这段代码,可以...
- **abhorrent** (adj): 可恨的、讨厌的。例句:The idea of eating insects is abhorrent to many people. - **abide** (v): 容忍或忍受。例句:Despite the hardships, she chose to abide by her principles. ...
1. 风能发电:风力是可再生能源,通过风力发电机可以转化为电力,为人类生活提供清洁的能源。 2. 调节气候:自然界的风有助于平衡各地的热量分布,防止极端气候的发生。 3. 自然界的韵律:风声给人带来宁静和舒适,...
骗子因为他们的狡猾和伪善被视为最可恨;大臣们的虚伪愚昧、阿谀奉承使他们成为最卑鄙的角色;而孩子的纯真无畏、直言不讳则赢得了最可爱的评价。骗子之所以能在光天化日之下行骗,是因为人们害怕暴露自己的愚蠢和...
CSDN上有些貌似的资源不过可惜的还是MFC的翻版,让人可恨的是,抄别人的代码,你也改改文件名,函数明吧,你就把别人的代码拿过来删掉全部的注释,然后就说自己开发,垃圾。 这个是我在www.codeproject.com上找到的...
语言:English 如果您要使用可恨的单词,此扩展程序会发出警告。 该工具旨在让您在使用可恶的语言鲁ck之前三思而后行。 它是为Peacehack2016创建的,Hatebase用于单词列表。
OpenDNS DNSCrypt,终于有工具可以对付可恨的 DNS污染 DNS劫持 了。这个是Windows版
清理档案加强版,简单的系统垃圾文件清理工具,免费的哦, 要分的人真可恨
软件测试时候发现根本没有需求,一问开发和需求,发现原来是我们的项目经理口口相传,告诉开发要怎么怎么做。 可想而之,这个过程是没有设计的,开发过程当中遇到问题,就会问,项目经理...更可恨地是部门经理说测试
音频属性查看器,找了半天,CSDN上面有一个要5分的,太可恨了,传上来分享一下,多多支持!!!
数字与模拟通信系统课后题答案2,这答案有个哥们恶心人的要10个积分,丧心病狂啊,大家还都是学生,我哪儿来那么多分,可恨
昨晚,本人电脑遭遇大量病毒及木马的侵袭,刚升级的杀毒软件及木马克星也无济于事,于是在安全模式下将这几个可恨的文件一删了之,而且将这一时段生成的所有文件,不管格式及后缀,全部删除,重启电脑后无异常,但当...